summaryrefslogtreecommitdiffstats
path: root/src/Runtime
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-04-02 16:12:08 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-05-07 08:47:05 +0000
commit988f62c763eef90e4dafe9ecf6bb05629279278e (patch)
treee5ea6c42f5fba693ca9bd419f71ac69d7e34ca9a /src/Runtime
parentfe0a5a474392de0036019f0083a4401863508a83 (diff)
Add dynamic object creation to presentation C++ API
A new model element can be dynamically created into the scene. The slide and properties of the element can be specified at creation time. A material element is automatically created for each added model. The material is specified with a custom "material" property in the list of creation properties. Task-number: QT3DS-3209 Change-Id: I52b0e929023092110820405473a9399b67a305cd Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Diffstat (limited to 'src/Runtime')
-rw-r--r--src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.cpp1
-rw-r--r--src/Runtime/Source/engine/Qt3DSRuntimeView.cpp35
-rw-r--r--src/Runtime/Source/engine/Qt3DSRuntimeView.h9
-rw-r--r--src/Runtime/Source/foundation/StringTable.h2
-rw-r--r--src/Runtime/Source/runtime/Qt3DSIScene.h20
-rw-r--r--src/Runtime/Source/runtime/Qt3DSIScriptBridge.h18
-rw-r--r--src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp307
-rw-r--r--src/Runtime/Source/runtime/Qt3DSSlideSystem.cpp156
-rw-r--r--src/Runtime/Source/runtime/Qt3DSSlideSystem.h2
-rw-r--r--src/Runtime/Source/viewer/Qt3DSViewerApp.cpp9
-rw-r--r--src/Runtime/Source/viewer/Qt3DSViewerApp.h3
11 files changed, 463 insertions, 99 deletions
diff --git a/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.cpp b/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.cpp
index 8ba76fd1..f737ec4a 100644
--- a/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.cpp
+++ b/src/Runtime/Source/engine/Qt3DSRenderRuntimeBinding.cpp
@@ -197,6 +197,7 @@ struct Qt3DSRenderScene : public Q3DStudio::IScene
}
}
+ qt3ds::NVAllocatorCallback &allocator() override { return m_LoadData->m_AutoAllocator; }
Q3DStudio::IPresentation &GetPresentation() override { return *m_RuntimePresentation; }
// Update really just adds objects to the dirty set
diff --git a/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp b/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp
index b582195b..abff8f09 100644
--- a/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp
+++ b/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp
@@ -46,6 +46,7 @@
#include "Qt3DSRenderContextCore.h"
#include "Qt3DSRenderer.h"
#include "Qt3DSRenderBufferManager.h"
+#include "Qt3DSRenderRuntimeBindingImpl.h"
#include "Qt3DSDLLManager.h"
#include "foundation/Qt3DSSimpleTypes.h"
@@ -214,7 +215,10 @@ public:
float dataInputMax(const QString &name) const override;
float dataInputMin(const QString &name) const override;
- void SetAttribute(const char *elementPath, const char *attributeName, const char *value) override;
+ void createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties) override;
+ void SetAttribute(const char *elementPath, const char *attributeName,
+ const char *value) override;
bool GetAttribute(const char *elementPath, const char *attributeName, void *value) override;
void FireEvent(const char *element, const char *evtName) override;
bool PeekCustomAction(char *&outElementPath, char *&outActionName) override;
@@ -579,9 +583,11 @@ void CRuntimeView::SetDataInputValue(
const QString &name, const QVariant &value,
Q3DSDataInput::ValueRole property = Q3DSDataInput::ValueRole::Value)
{
- Q3DStudio::CQmlEngine &theBridgeEngine
- = static_cast<Q3DStudio::CQmlEngine &>(m_RuntimeFactoryCore->GetScriptEngineQml());
- theBridgeEngine.SetDataInputValue(name, value, property);
+ if (m_Application) {
+ Q3DStudio::CQmlEngine &theBridgeEngine
+ = static_cast<Q3DStudio::CQmlEngine &>(m_RuntimeFactoryCore->GetScriptEngineQml());
+ theBridgeEngine.SetDataInputValue(name, value, property);
+ }
}
QList<QString> CRuntimeView::dataInputs() const
@@ -594,12 +600,29 @@ QList<QString> CRuntimeView::dataInputs() const
float CRuntimeView::dataInputMax(const QString &name) const
{
- return m_Application->dataInputMax(name);
+ if (m_Application)
+ return m_Application->dataInputMax(name);
+
+ return 0;
}
float CRuntimeView::dataInputMin(const QString &name) const
{
- return m_Application->dataInputMin(name);
+ if (m_Application)
+ return m_Application->dataInputMin(name);
+
+ return 0;
+}
+
+void CRuntimeView::createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties)
+{
+ if (m_Application) {
+ Q3DStudio::CQmlEngine &theBridgeEngine
+ = static_cast<Q3DStudio::CQmlEngine &>(m_RuntimeFactoryCore->GetScriptEngineQml());
+ theBridgeEngine.createElement(parentElementPath, slideName, properties,
+ &m_RuntimeFactory->GetQt3DSRenderContext().GetRenderer());
+ }
}
void CRuntimeView::SetAttribute(const char *elementPath, const char *attributeName, const char *value)
diff --git a/src/Runtime/Source/engine/Qt3DSRuntimeView.h b/src/Runtime/Source/engine/Qt3DSRuntimeView.h
index 7b9a5945..3626fd52 100644
--- a/src/Runtime/Source/engine/Qt3DSRuntimeView.h
+++ b/src/Runtime/Source/engine/Qt3DSRuntimeView.h
@@ -46,10 +46,6 @@
#include <QtCore/qobject.h>
#include <QtGui/qsurfaceformat.h>
-//==============================================================================
-// Namespace
-//==============================================================================
-
typedef void (*qml_Function)(void *inUserData);
class QRuntimeViewSignalProxy : public QObject
@@ -73,9 +69,6 @@ class NVRenderContext;
namespace Q3DStudio {
-//==============================================================================
-// Forwards
-//==============================================================================
class CTegraInputEngine;
class CTegraRenderEngine;
class IScene;
@@ -196,6 +189,8 @@ public:
virtual QList<QString> dataInputs() const = 0;
virtual float dataInputMax(const QString &name) const = 0;
virtual float dataInputMin(const QString &name) const = 0;
+ virtual void createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties) = 0;
virtual void SetAttribute(const char *elementPath, const char *attributeName,
const char *value) = 0;
virtual bool GetAttribute(const char *elementPath, const char *attributeName, void *value) = 0;
diff --git a/src/Runtime/Source/foundation/StringTable.h b/src/Runtime/Source/foundation/StringTable.h
index c7c62199..123992cc 100644
--- a/src/Runtime/Source/foundation/StringTable.h
+++ b/src/Runtime/Source/foundation/StringTable.h
@@ -49,6 +49,8 @@
#include "foundation/Qt3DSDataRef.h"
#include "foundation/Qt3DSOption.h"
+#include <QtCore/qstring.h>
+
namespace qt3ds {
namespace foundation {
typedef char8_t Qt3DSBChar;
diff --git a/src/Runtime/Source/runtime/Qt3DSIScene.h b/src/Runtime/Source/runtime/Qt3DSIScene.h
index 3f80f85f..83347e11 100644
--- a/src/Runtime/Source/runtime/Qt3DSIScene.h
+++ b/src/Runtime/Source/runtime/Qt3DSIScene.h
@@ -38,21 +38,15 @@ namespace qt3ds {
namespace render {
class IImageLoadListener;
}
+ class NVAllocatorCallback;
}
-//==============================================================================
-// Namespace
-//==============================================================================
namespace Q3DStudio {
-//==============================================================================
-// Forwards
-//==============================================================================
class IPresentation;
class RuntimeMatrix;
struct SPickFrame;
-//==============================================================================
/**
* @interface IScene
*
@@ -110,9 +104,6 @@ struct SCameraRect
class IScene
{
- //==============================================================================
- // Methods
- //==============================================================================
protected:
virtual ~IScene() {}
@@ -122,8 +113,6 @@ public: // Base Interface
virtual void SetUserData(void *inUserData) = 0;
virtual void *GetUserData() = 0;
- // virtual void Clone( TElementList& inElements, TElementList& inElementClones, TElement*
- // inNewParent = NULL ) = 0;
virtual void CalculateGlobalTransform(TElement *inElement, RuntimeMatrix &outTransform) = 0;
virtual void SetLocalTransformMatrix(TElement *inElement, const RuntimeMatrix &inTransform) = 0;
// Get bounding box in global space
@@ -147,8 +136,7 @@ public: // Base Interface
virtual STextSizes GetPresentationDesignDimensions() = 0;
// If the rect's right - left == 0.0, this method failed. Possibly because the layer is just
- // direct-rendering
- // a sub-presentation.
+ // direct-rendering a sub-presentation.
virtual SCameraRect GetCameraBounds(TElement &inElement) = 0;
virtual void PositionToScreen(TElement &inElement, qt3ds::QT3DSVec3 &inPos,
@@ -161,13 +149,15 @@ public: // Base Interface
virtual Q3DStudio::INT32
LoadImageBatch(qt3ds::foundation::CRegisteredString *inFullPaths, INT32 inNumPaths,
qt3ds::foundation::CRegisteredString inDefaultImage,
- qt3ds::render::IImageLoadListener *inLoadCallback = NULL) = 0;
+ qt3ds::render::IImageLoadListener *inLoadCallback = nullptr) = 0;
virtual SMousePosition WindowToPresentation(const SMousePosition &inWindowPos) = 0;
virtual void RegisterOffscreenRenderer(const char *inKey) = 0;
virtual void Release() = 0;
+
+ virtual qt3ds::NVAllocatorCallback &allocator() = 0;
};
} // namespace Q3DStudio
diff --git a/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h b/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h
index 4be6fe16..3b26abd2 100644
--- a/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h
+++ b/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h
@@ -35,9 +35,8 @@
#include "foundation/Qt3DSRefCounted.h"
#include "q3dsdatainput.h"
-//==============================================================================
-// Namespace
-//==============================================================================
+#include <QtCore/qvariant.h>
+
namespace qt3ds {
namespace runtime {
class IApplication;
@@ -53,6 +52,7 @@ namespace state {
namespace qt3ds {
namespace render {
class IThreadPool;
+ class IQt3DSRenderer;
}
}
@@ -60,13 +60,9 @@ struct script_State;
namespace Q3DStudio {
-//==============================================================================
-// Forwards
-//==============================================================================
struct SEventCommand;
class IPresentation;
-//==============================================================================
/**
* @interface IScriptBridge
* @brief Callback and load interface for a script engine.
@@ -116,10 +112,7 @@ protected:
class IScriptBridge : public qt3ds::foundation::NVRefCounted
{
- //==============================================================================
- // Methods
- //==============================================================================
-public: // Construction
+public:
virtual ~IScriptBridge() {}
public: // thread
@@ -165,6 +158,9 @@ public: // Elements
virtual void SetDataInputValue(
const QString &name, const QVariant &value,
Q3DSDataInput::ValueRole property = Q3DSDataInput::ValueRole::Value) = 0;
+ virtual void createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties,
+ qt3ds::render::IQt3DSRenderer *renderer) = 0;
public: // Components
virtual void GotoSlide(const char *component, const char *slideName,
diff --git a/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp b/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp
index 0898df70..23a097a7 100644
--- a/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp
+++ b/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp
@@ -48,6 +48,7 @@
#include "foundation/Qt3DSBroadcastingAllocator.h"
#include "Qt3DSRenderInputStreamFactory.h"
#include "Qt3DSSlideSystem.h"
+#include "Qt3DSRenderModel.h"
#include "EASTL/vector.h"
#include "EASTL/list.h"
@@ -66,6 +67,9 @@
#include "Qt3DSParametersSystem.h"
#include "Qt3DSQmlElementHelper.h"
#include "q3dsqmlscript.h"
+#include "Qt3DSRenderRuntimeBindingImpl.h"
+#include "Qt3DSRenderBufferManager.h" // TODO: Needed for adding meshes dynamically (QT3DS-3378)
+#include "Qt3DSRenderer.h"
#include <QtQml/qqmlengine.h>
#include <QtQml/qqmlcontext.h>
@@ -413,6 +417,11 @@ public:
void FireEvent(const char *element, const char *evtName) override;
void SetDataInputValue(const QString &name, const QVariant &value,
Q3DSDataInput::ValueRole valueRole) override;
+ void createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties,
+ qt3ds::render::IQt3DSRenderer *renderer) override;
+ //void createMaterial() override; // TODO (QT3DS-3377)
+ //void createMesh() override; // TODO (QT3DS-3378)
void GotoSlide(const char *component, const char *slideName,
const SScriptEngineGotoSlideArgs &inArgs) override;
@@ -817,6 +826,304 @@ void CQmlEngineImpl::SetDataInputValue(
}
}
+using TPropertyDescAndValueList = eastl::vector<qt3ds::runtime::element::TPropertyDescAndValue>;
+using TPropertyDesc = qt3ds::runtime::element::SPropertyDesc;
+
+void CQmlEngineImpl::createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties,
+ qt3ds::render::IQt3DSRenderer *renderer)
+{
+ // Resolve parent element
+ QByteArray theParentPath = parentElementPath.toUtf8();
+ TElement *parentElement = getTarget(theParentPath.constData());
+
+ if (!parentElement) {
+ qWarning() << __FUNCTION__ << "Invalid parent element:" << parentElementPath;
+ return;
+ }
+
+ auto parentTranslator = static_cast<qt3ds::render::Qt3DSTranslator *>(
+ parentElement->GetAssociation());
+
+ if (!parentTranslator || !qt3ds::render::GraphObjectTypes::IsNodeType(
+ parentTranslator->GetUIPType())) {
+ qWarning() << __FUNCTION__ << "Parent element is not a valid node";
+ return;
+ }
+
+ TElement &component = parentElement->GetComponentParent();
+ auto &parentObject = static_cast<qt3ds::render::SNode &>(parentTranslator->RenderObject());
+
+ IPresentation *presentation = parentElement->GetBelongedPresentation();
+
+ static int idCounter = 0;
+ ++idCounter;
+
+ // Resolve slide
+ QByteArray theSlideName = slideName.toUtf8();
+ ISlideSystem &slideSystem = presentation->GetSlideSystem();
+ int slideIndex = slideSystem.FindSlide(component, theSlideName.constData());
+ int currentSlide = static_cast<TComponent &>(component).GetCurrentSlide();
+ if (slideIndex == 0xff) {
+ qWarning() << __FUNCTION__ << "Invalid slide name for time context:" << slideName;
+ return;
+ }
+
+ // Remove properties requiring custom handling
+ QHash<QString, QVariant> theProperties = properties;
+ QString newElementName = theProperties.take(QStringLiteral("name")).toString();
+ QString refMatName = theProperties.take(QStringLiteral("material")).toString();
+ if (refMatName.startsWith(QLatin1Char('#'))) // Absolute reference
+ refMatName = refMatName.mid(1);
+ else if (!refMatName.isEmpty() && !refMatName.contains(QLatin1Char('/')))
+ refMatName = QStringLiteral("/") + refMatName;
+
+ if (newElementName.isEmpty())
+ newElementName = QStringLiteral("NewElement_%1").arg(idCounter);
+ QByteArray newElementNameBa = newElementName.toUtf8();
+
+ // Make sure the name is not duplicate
+ TElement *existingChild
+ = parentElement->FindChild(CHash::HashString(newElementNameBa.constData()));
+ if (existingChild) {
+ qWarning() << __FUNCTION__
+ << "The specified parent" << parentElementPath
+ << "already has a child with the same name:" << newElementName;
+ return;
+ }
+
+ auto &strTable = presentation->GetStringTable();
+ const CRegisteredString regName = strTable.RegisterStr(newElementNameBa);
+ // TODO: Support also some non-model element types, like group and text elements (QT3DS-3381)
+ const CRegisteredString elementType = strTable.RegisterStr("Model");
+ const CRegisteredString elementSubType;
+ TPropertyDescAndValueList elementProperties;
+
+ // Set properties
+ auto addStringAttribute = [&strTable](TPropertyDescAndValueList &list,
+ const QString &inAttName, const QString &inValue) {
+ QByteArray valueBa = inValue.toUtf8();
+ qt3ds::foundation::CStringHandle strHandle = strTable.GetHandle(valueBa.constData());
+ UVariant theValue;
+ theValue.m_StringHandle = strHandle.handle();
+ const CRegisteredString attStr = strTable.RegisterStr(inAttName);
+ list.push_back(
+ eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_STRING), theValue));
+ };
+ auto addIntAttribute = [&strTable](TPropertyDescAndValueList &list, const QString &inAttName,
+ int inValue) {
+ UVariant theValue;
+ theValue.m_INT32 = inValue;
+ const CRegisteredString attStr = strTable.RegisterStr(inAttName);
+ list.push_back(
+ eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_INT32), theValue));
+ };
+ auto addBoolAttribute = [&strTable](TPropertyDescAndValueList &list,
+ const QString &inAttName, bool inValue) {
+ UVariant theValue;
+ theValue.m_INT32 = int(inValue);
+ const CRegisteredString attStr = strTable.RegisterStr(inAttName);
+ list.push_back(
+ eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_BOOL), theValue));
+ };
+ auto addFloatAttribute = [&strTable](TPropertyDescAndValueList &list, const QString &inAttName,
+ float inValue) {
+ UVariant theValue;
+ theValue.m_FLOAT = inValue;
+ const CRegisteredString attStr = strTable.RegisterStr(inAttName);
+ list.push_back(
+ eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_FLOAT), theValue));
+ };
+ auto addFloat3Attribute = [&strTable](TPropertyDescAndValueList &list,
+ const QStringList &inAttNames, const QVector3D &inValue) {
+ for (int i = 0; i < 3; ++i) {
+ UVariant theValue;
+ theValue.m_FLOAT = inValue[i];
+ const CRegisteredString attStr = strTable.RegisterStr(inAttNames.at(i));
+ list.push_back(
+ eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_FLOAT), theValue));
+ }
+ };
+
+ // Set default values for missing mandatory properties
+ const QString sourcePathPropName = QStringLiteral("sourcepath");
+ const QString startTimePropName = QStringLiteral("starttime");
+ const QString endTimePropName = QStringLiteral("endtime");
+ const QString eyeBallPropName = QStringLiteral("eyeball");
+ Q3DStudio::UVariant attValue;
+ bool eyeBall = true;
+ theProperties.value(QStringLiteral("eyeball"), true).toBool();
+ if (!theProperties.contains(sourcePathPropName))
+ addStringAttribute(elementProperties, sourcePathPropName, QStringLiteral("#Cube"));
+ if (!theProperties.contains(startTimePropName)) {
+ parentElement->GetAttribute(Q3DStudio::ATTRIBUTE_STARTTIME, attValue);
+ addIntAttribute(elementProperties, startTimePropName, int(attValue.m_INT32));
+ }
+ if (!theProperties.contains(endTimePropName)) {
+ parentElement->GetAttribute(Q3DStudio::ATTRIBUTE_ENDTIME, attValue);
+ addIntAttribute(elementProperties, endTimePropName, int(attValue.m_INT32));
+ }
+ if (!theProperties.contains(eyeBallPropName))
+ addBoolAttribute(elementProperties, eyeBallPropName, true);
+ else
+ eyeBall = theProperties.value(QStringLiteral("eyeball")).toBool();
+
+ QHashIterator<QString, QVariant> it(theProperties);
+ while (it.hasNext()) {
+ it.next();
+ switch (it.value().type()) {
+ case QVariant::Double:
+ addFloatAttribute(elementProperties, it.key(), it.value().toFloat());
+ break;
+ case QVariant::Bool:
+ addBoolAttribute(elementProperties, it.key(), it.value().toBool());
+ break;
+ case QVariant::Int:
+ addIntAttribute(elementProperties, it.key(), it.value().toInt());
+ break;
+ case QVariant::String:
+ addStringAttribute(elementProperties, it.key(), it.value().toString());
+ break;
+ case QVariant::Vector3D: {
+ QVector3D vec = it.value().value<QVector3D>();
+ if (it.key() == QLatin1String("rotation")) {
+ vec.setX(qDegreesToRadians(vec.x()));
+ vec.setY(qDegreesToRadians(vec.y()));
+ vec.setZ(qDegreesToRadians(vec.z()));
+ }
+ // TODO: Need to support also colors if non-model elements what need colors are
+ // TODO: supported (QT3DS-3381)
+ QStringList atts;
+ atts << (it.key() + QLatin1String(".x"))
+ << (it.key() + QLatin1String(".y"))
+ << (it.key() + QLatin1String(".z"));
+ addFloat3Attribute(elementProperties, atts, vec);
+ break;
+ }
+ default:
+ qWarning() << __FUNCTION__ << "Unsupported property type for" << it.key();
+ break;
+ }
+ }
+
+ // Create new element
+ TElement &newElem = m_Application->GetElementAllocator().CreateElement(
+ regName, elementType, elementSubType,
+ toConstDataRef(elementProperties.data(), QT3DSU32(elementProperties.size())),
+ presentation, parentElement, false);
+
+ QString elementPath = parentElementPath + QLatin1Char('.') + newElementName;
+ newElem.m_Path = strTable.RegisterStr(elementPath);
+
+ // Insert the new element into the correct slide
+ if (!slideSystem.addSlideElement(component, slideIndex, newElem, eyeBall)) {
+ qWarning() << __FUNCTION__ << "Failed to add the new element to a slide";
+ // Delete created element if adding to slide failed
+ m_Application->GetElementAllocator().ReleaseElement(newElem, true);
+ 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 = elementPath + QLatin1String(".refmat");
+ newMatElem.m_Path = strTable.RegisterStr(matElemPath);
+
+ if (!slideSystem.addSlideElement(component, slideIndex, newMatElem, eyeBall)) {
+ qWarning() << __FUNCTION__ << "Failed to add the new material element to a slide";
+ // Delete created element and material element if adding to slide failed
+ m_Application->GetElementAllocator().ReleaseElement(newElem, true);
+ 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<qt3ds::render::Qt3DSTranslator *>(
+ nextChild->GetAssociation());
+ referencedMaterial = static_cast<qt3ds::render::SGraphObject *>(
+ &tr->RenderObject());
+ break;
+ }
+ 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<qt3ds::render::Qt3DSTranslator *>(firstChild->GetAssociation());
+ referencedMaterial = static_cast<qt3ds::render::SGraphObject *>(&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.
+ qWarning() << __FUNCTION__ << "Unable to resolve a fallback material";
+ m_Application->GetElementAllocator().ReleaseElement(newElem, true);
+ return;
+ }
+ }
+
+ // Create new SGraphObject (SNode)
+ NVAllocatorCallback &allocator = presentation->GetScene()->allocator();
+ qt3ds::render::SModel *newObject = QT3DS_NEW(allocator, qt3ds::render::SModel)();
+ newObject->m_Id = strTable.RegisterStr((QByteArrayLiteral("_newObject_")
+ + QByteArray::number(idCounter)).constData());
+ parentObject.AddChild(*newObject);
+
+ qt3ds::render::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);
+
+ // Determine if element should be active based on start/end times
+ TTimeUnit startTime = 0;
+ TTimeUnit stopTime = 0;
+ if (newElem.GetAttribute(Q3DStudio::ATTRIBUTE_STARTTIME, attValue))
+ startTime = TTimeUnit(attValue.m_INT32);
+ if (newElem.GetAttribute(Q3DStudio::ATTRIBUTE_ENDTIME, attValue))
+ stopTime = TTimeUnit(attValue.m_INT32);
+ TTimeUnit localTime = newElem.GetActivityZone().GetItemLocalTime(newElem);
+
+ bool isActiveRightNow = eyeBall && localTime >= startTime && localTime <= stopTime
+ && currentSlide == slideIndex;
+
+ newElem.SetActive(isActiveRightNow);
+ newObject->m_Flags.SetActive(isActiveRightNow);
+ if (eyeBall)
+ newElem.GetActivityZone().UpdateItemInfo(newElem);
+
+ renderer->ChildrenUpdated(parentObject);
+}
+
void CQmlEngineImpl::GotoSlide(const char *component, const char *slideName,
const SScriptEngineGotoSlideArgs &inArgs)
{
diff --git a/src/Runtime/Source/runtime/Qt3DSSlideSystem.cpp b/src/Runtime/Source/runtime/Qt3DSSlideSystem.cpp
index 524422f4..3e2f95c2 100644
--- a/src/Runtime/Source/runtime/Qt3DSSlideSystem.cpp
+++ b/src/Runtime/Source/runtime/Qt3DSSlideSystem.cpp
@@ -48,10 +48,9 @@ using namespace qt3ds::runtime::element;
namespace {
struct SSlideAttribute
{
- QT3DSU32 m_Index;
+ QT3DSU32 m_Index = 0;
Q3DStudio::UVariant m_Value;
SSlideAttribute()
- : m_Index(0)
{
m_Value.m_INT32 = 0;
}
@@ -69,12 +68,7 @@ struct SSlideAttributeNode
};
SSlideAttribute m_Data[AttributeCount];
- SSlideAttributeNode *m_NextNode;
-
- SSlideAttributeNode()
- : m_NextNode(nullptr)
- {
- }
+ SSlideAttributeNode *m_NextNode = nullptr;
};
typedef IndexableLinkedList<SSlideAttributeNode, SSlideAttribute,
@@ -83,18 +77,15 @@ typedef IndexableLinkedList<SSlideAttributeNode, SSlideAttribute,
struct SSlideElement
{
- QT3DSU32 m_ElementHandle;
+ QT3DSU32 m_ElementHandle = 0;
QT3DSU32 m_AttributeCount : 31;
QT3DSU32 m_Active : 1;
- SSlideElement *m_NextElement;
- SSlideAttributeNode *m_AttributeNodes;
+ SSlideElement *m_NextElement = nullptr;
+ SSlideAttributeNode *m_AttributeNodes = nullptr;
SSlideElement()
- : m_ElementHandle(0)
- , m_AttributeCount(0)
+ : m_AttributeCount(0)
, m_Active(false)
- , m_NextElement(nullptr)
- , m_AttributeNodes(nullptr)
{
}
};
@@ -105,11 +96,7 @@ struct SSlideAnimActionNode
AnimActionCount = 8,
};
SSlideAnimAction m_Data[AnimActionCount];
- SSlideAnimActionNode *m_NextNode;
- SSlideAnimActionNode()
- : m_NextNode(nullptr)
- {
- }
+ SSlideAnimActionNode *m_NextNode = nullptr;
};
typedef IndexableLinkedList<SSlideAnimActionNode, SSlideAnimAction,
@@ -118,32 +105,25 @@ typedef IndexableLinkedList<SSlideAnimActionNode, SSlideAnimAction,
struct SSlide
{
- SSlide *m_NextSlide;
+ SSlide *m_NextSlide = nullptr;
CRegisteredString m_Name;
QT3DSU32 m_PlayMode : 3;
QT3DSU32 m_PlayThroughTo : 8; // OXFF means no playthrough
QT3DSU32 m_Paused : 1;
- QT3DSU32 m_StartTime;
- QT3DSU32 m_EndTime;
- QT3DSU32 m_AnimActionCount;
- SSlideElement *m_FirstElement;
- SSlideAnimActionNode *m_FirstAnimActionNode;
+ QT3DSU32 m_StartTime = 0;
+ QT3DSU32 m_EndTime = 0;
+ QT3DSU32 m_AnimActionCount = 0;
+ SSlideElement *m_FirstElement = nullptr;
+ SSlideElement *m_lastElement = nullptr;
+ SSlideAnimActionNode *m_FirstAnimActionNode = nullptr;
+ bool m_activeSlide = false;
+ bool m_unloadSlide = false;
QVector<QString> m_sourcePaths;
- bool m_activeSlide;
- bool m_unloadSlide;
SSlide()
- : m_NextSlide(nullptr)
- , m_PlayMode(PlayMode::StopAtEnd)
+ : m_PlayMode(PlayMode::StopAtEnd)
, m_PlayThroughTo(0xFF)
, m_Paused(false)
- , m_StartTime(0)
- , m_EndTime(0)
- , m_AnimActionCount(0)
- , m_FirstElement(nullptr)
- , m_FirstAnimActionNode(nullptr)
- , m_activeSlide(false)
- , m_unloadSlide(false)
{
}
@@ -172,12 +152,12 @@ struct SSlideSystem : public ISlideSystem
IElementAllocator &m_ElementSystem;
TAttributeNodePool m_AttributeNodePool;
TSlideAnimActionPool m_AnimActionPool;
- TSlideElementPool m_SlideElements;
TSlidePool m_SlidePool;
+ TSlideElementPool m_SlideElements;
TComponentSlideHash m_Slides;
- SSlide *m_CurrentSlide;
- SSlideElement *m_CurrentSlideElement;
+ SSlide *m_CurrentSlide = nullptr;
+ SSlideElement *m_CurrentSlideElement = nullptr;
NVDataRef<QT3DSU8> m_LoadData;
@@ -192,8 +172,6 @@ struct SSlideSystem : public ISlideSystem
, m_SlidePool(ForwardingAllocator(inFnd.getAllocator(), "m_SlidePool"))
, m_SlideElements(ForwardingAllocator(inFnd.getAllocator(), "m_SlideElements"))
, m_Slides(inFnd.getAllocator(), "m_Slides")
- , m_CurrentSlide(nullptr)
- , m_CurrentSlideElement(nullptr)
, m_RefCount(0)
{
}
@@ -214,14 +192,14 @@ struct SSlideSystem : public ISlideSystem
QT3DSU32 inMinTime, QT3DSU32 inMaxTime) override
{
eastl::pair<TComponentSlideHash::iterator, bool> inserter =
- m_Slides.insert(eastl::make_pair(&inComponent, (SSlide *)nullptr));
+ m_Slides.insert(eastl::make_pair(&inComponent, static_cast<SSlide *>(nullptr)));
SSlide *newSlide = m_SlidePool.construct(__FILE__, __LINE__);
QT3DSU32 slideIndex = 0;
- if (inserter.first->second == nullptr) {
+ if (!inserter.first->second) {
inserter.first->second = newSlide;
} else {
SSlide *theSlide = nullptr;
- for (theSlide = inserter.first->second; theSlide->m_NextSlide != nullptr;
+ for (theSlide = inserter.first->second; theSlide->m_NextSlide;
theSlide = theSlide->m_NextSlide) {
++slideIndex;
}
@@ -254,32 +232,91 @@ struct SSlideSystem : public ISlideSystem
void SetSlideMaxTime(QT3DSU32 inMaxTime) override
{
- if (m_CurrentSlide != nullptr)
+ if (m_CurrentSlide)
m_CurrentSlide->m_EndTime = inMaxTime;
}
void AddSlideElement(element::SElement &inElement, bool inActive) override
{
- if (m_CurrentSlide != nullptr) {
+ if (m_CurrentSlide) {
SSlideElement *lastSlideElement = m_CurrentSlideElement;
m_CurrentSlideElement = m_SlideElements.construct(__FILE__, __LINE__);
m_CurrentSlideElement->m_Active = inActive;
m_CurrentSlideElement->m_ElementHandle = inElement.GetHandle();
- if (lastSlideElement == nullptr) {
- QT3DS_ASSERT(m_CurrentSlide->m_FirstElement == nullptr);
+ if (!lastSlideElement) {
+ QT3DS_ASSERT(!m_CurrentSlide->m_FirstElement);
m_CurrentSlide->m_FirstElement = m_CurrentSlideElement;
} else {
lastSlideElement->m_NextElement = m_CurrentSlideElement;
}
- m_CurrentSlideElement->m_Active = inActive;
+ m_CurrentSlide->m_lastElement = m_CurrentSlideElement;
} else {
QT3DS_ASSERT(false);
}
}
- void AddSlideAttribute(Q3DStudio::SAttributeKey inKey, Q3DStudio::UVariant inValue) override
+
+
+ // The parent element must be found from target slide.
+ // Elements cannot be added to the master slide.
+ bool addSlideElement(element::SElement &inComponent, int slideIndex,
+ element::SElement &inElement, bool eyeBall) override
{
- if (m_CurrentSlideElement != nullptr) {
+ // Note: Slide 0 contains all loaded items in the graph with m_active set to false.
+ // Other slides contain all master slide items and slide specific items with m_active
+ // set to eyeball. We shouldn't need to care about slide 0 here as it won't be
+ // executed/rolled back after initial loading of the scene.
+
+ Q_ASSERT(slideIndex > 0);
+ TComponentSlideHash::const_iterator theFindResult = m_Slides.find(&inComponent);
+ element::SElement *parentElement = inElement.GetParent();
+ if (theFindResult == m_Slides.end()) {
+ qWarning() << __FUNCTION__ << "Could not find slides for component";
+ return false;
+ }
+ if (!parentElement) {
+ qWarning() << __FUNCTION__ << "Element has no parent";
+ return false;
+ }
+
+ int parentFound = false;
+ SSlide *slide = theFindResult->second;
+ SSlide *targetSlide = nullptr;
+ for (int idx = 0; slide && !targetSlide; slide = slide->m_NextSlide, ++idx) {
+ if (slideIndex == idx) {
+ targetSlide = slide;
+ SSlideElement *slideElement = slide->m_FirstElement;
+ while (slideElement) {
+ if (slideElement->m_ElementHandle == parentElement->m_Handle) {
+ parentFound = true;
+ break;
+ }
+ slideElement = slideElement->m_NextElement;
+ }
+ }
+ }
+
+ if (!parentFound) {
+ qWarning() << __FUNCTION__ << "Parent element could not be found from target slide";
+ return false;
+ }
+
+ m_CurrentSlide = targetSlide;
+ m_CurrentSlideElement = m_CurrentSlide->m_lastElement;
+
+ // Explicit active state is based solely on the slide and eyeball
+ int activeSlideIndex = static_cast<SComponent &>(inComponent).GetCurrentSlide();
+ bool isActive = activeSlideIndex == slideIndex && eyeBall;
+ inElement.Flags().SetExplicitActive(isActive);
+
+ AddSlideElement(inElement, eyeBall);
+
+ return true;
+ }
+
+ void AddSlideAttribute(Q3DStudio::SAttributeKey inKey, Q3DStudio::UVariant inValue) override
+ {
+ if (m_CurrentSlideElement) {
SElement *theElement =
m_ElementSystem.FindElementByHandle(m_CurrentSlideElement->m_ElementHandle);
Option<QT3DSU32> theIdx = theElement->FindPropertyIndex(inKey.m_Hash);
@@ -297,12 +334,12 @@ struct SSlideSystem : public ISlideSystem
SSlideAnimAction *AddSlideAnimAction(bool inAnimation, QT3DSI32 inId, bool inActive) override
{
- if (m_CurrentSlide != nullptr) {
+ if (m_CurrentSlide) {
SSlideAnimAction &theAnimAction = TSlideAnimActionNodeList::Create(
m_CurrentSlide->m_FirstAnimActionNode, m_CurrentSlide->m_AnimActionCount,
m_AnimActionPool);
- theAnimAction = SSlideAnimAction((QT3DSI32)inId, inActive, inAnimation);
- &theAnimAction;
+ theAnimAction = SSlideAnimAction(QT3DSI32(inId), inActive, inAnimation);
+ return &theAnimAction;
}
return nullptr;
@@ -451,17 +488,16 @@ struct SSlideSystem : public ISlideSystem
void InitializeDynamicKeys(SSlideKey inKey, IAnimationSystem &inAnimationSystem) const override
{
const SSlide *theSlide = FindSlide(inKey);
- if (theSlide != nullptr) {
+ if (theSlide) {
IterateSlideAnimActions(*theSlide, SDynamicKeyOperator(inAnimationSystem));
}
}
void ExecuteSlide(SSlideKey inKey, IAnimationSystem &inAnimationSystem,
- ILogicSystem &inLogicManager) override
+ ILogicSystem &inLogicManager) override
{
SSlide *theSlide = FindSlide(inKey);
-
- if (theSlide == nullptr) {
+ if (!theSlide) {
QT3DS_ASSERT(false);
return;
}
@@ -503,7 +539,7 @@ struct SSlideSystem : public ISlideSystem
{
SSlide *theSlide = FindSlide(inKey);
- if (theSlide == nullptr) {
+ if (!theSlide) {
QT3DS_ASSERT(false);
return;
}
diff --git a/src/Runtime/Source/runtime/Qt3DSSlideSystem.h b/src/Runtime/Source/runtime/Qt3DSSlideSystem.h
index becc057f..3aa2a011 100644
--- a/src/Runtime/Source/runtime/Qt3DSSlideSystem.h
+++ b/src/Runtime/Source/runtime/Qt3DSSlideSystem.h
@@ -126,6 +126,8 @@ namespace runtime {
virtual void SetSlideMaxTime(QT3DSU32 inMaxTime) = 0;
virtual void AddSlideElement(element::SElement &inElement, bool inActive) = 0;
+ virtual bool addSlideElement(element::SElement &inComponent, int slideIndex,
+ element::SElement &inElement, bool eyeBall) = 0;
virtual void AddSlideAttribute(Q3DStudio::SAttributeKey inKey,
Q3DStudio::UVariant inValue) = 0;
virtual SSlideAnimAction *AddSlideAnimAction(bool inAnimation, QT3DSI32 inIndex,
diff --git a/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp b/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp
index c1cdd56e..005eedcd 100644
--- a/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp
+++ b/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp
@@ -794,6 +794,15 @@ float Q3DSViewerApp::dataInputMin(const QString &name) const
return m_Impl.m_view->dataInputMin(name);
}
+void Q3DSViewerApp::createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties)
+{
+ if (!m_Impl.m_view)
+ return;
+
+ m_Impl.m_view->createElement(parentElementPath, slideName, properties);
+}
+
Q3DSViewerApp &Q3DSViewerApp::Create(void *glContext, Q3DStudio::IAudioPlayer *inAudioPlayer,
QElapsedTimer *startupTimer)
{
diff --git a/src/Runtime/Source/viewer/Qt3DSViewerApp.h b/src/Runtime/Source/viewer/Qt3DSViewerApp.h
index ce7c63bf..a4bdc2e3 100644
--- a/src/Runtime/Source/viewer/Qt3DSViewerApp.h
+++ b/src/Runtime/Source/viewer/Qt3DSViewerApp.h
@@ -359,6 +359,9 @@ public:
float dataInputMax(const QString &name) const;
float dataInputMin(const QString &name) const;
+ void createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties);
+
QString error();
void setPresentationId(const QString &id);