diff options
Diffstat (limited to 'src/Runtime/ogl-runtime/src/runtime/Qt3DSQmlEngine.cpp')
m--------- | src/Runtime/ogl-runtime | 0 | ||||
-rw-r--r-- | src/Runtime/ogl-runtime/src/runtime/Qt3DSQmlEngine.cpp | 2690 |
2 files changed, 0 insertions, 2690 deletions
diff --git a/src/Runtime/ogl-runtime b/src/Runtime/ogl-runtime new file mode 160000 +Subproject 2025912174c4cf99270b7439ec3b021e1d089ae diff --git a/src/Runtime/ogl-runtime/src/runtime/Qt3DSQmlEngine.cpp b/src/Runtime/ogl-runtime/src/runtime/Qt3DSQmlEngine.cpp deleted file mode 100644 index ac958ea7..00000000 --- a/src/Runtime/ogl-runtime/src/runtime/Qt3DSQmlEngine.cpp +++ /dev/null @@ -1,2690 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 1993-2009 NVIDIA Corporation. -** Copyright (C) 2017 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt 3D Studio. -** -** $QT_BEGIN_LICENSE:GPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 or (at your option) any later version -** approved by the KDE Free Qt Foundation. The licenses are as published by -** the Free Software Foundation and appearing in the file LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "RuntimePrefix.h" - -//============================================================================== -// Includes -//============================================================================== -#include "Qt3DSQmlEngine.h" -#include "Qt3DSPresentation.h" -#include "Qt3DSInputEngine.h" -#include "Qt3DSSceneManager.h" -#include "Qt3DSVector3.h" -#include "Qt3DSColor.h" -#include "Qt3DSAttributeHashes.h" -#include "Qt3DSFileStream.h" -#include "Qt3DSDataLogger.h" -#include "render/Qt3DSRenderBaseTypes.h" -#include "foundation/FileTools.h" -#include "foundation/Qt3DSSystem.h" -#include "foundation/Qt3DSBroadcastingAllocator.h" -#include "Qt3DSRenderInputStreamFactory.h" -#include "Qt3DSSlideSystem.h" -#include "Qt3DSRenderModel.h" - -#include "EASTL/vector.h" -#include "EASTL/list.h" -#include <sys/stat.h> -#include "Qt3DSCommandEventTypes.h" -#include "Qt3DSApplication.h" -#include "Qt3DSRuntimeFactory.h" -#include "Qt3DSRenderContextCore.h" -#include "Qt3DSRenderInputStreamFactory.h" -#include "foundation/Qt3DSPerfTimer.h" -#include "Qt3DSRenderThreadPool.h" -#include "Qt3DSRenderImageBatchLoader.h" -#include "foundation/Qt3DSAtomic.h" -#include "Qt3DSAudioPlayer.h" -#include "Qt3DSActivationManager.h" -#include "Qt3DSParametersSystem.h" -#include "Qt3DSQmlElementHelper.h" -#include "q3dsqmlscript.h" -#include "Qt3DSRenderRuntimeBindingImpl.h" -#include "Qt3DSRenderBufferManager.h" -#include "Qt3DSImportMesh.h" -#include "Qt3DSRenderer.h" -#include "q3dsmaterialdefinitionparser.h" -#include "Qt3DSRenderCustomMaterialSystem.h" -#include "Qt3DSRenderDynamicObjectSystem.h" -#include "Qt3DSRenderMaterialHelpers.h" -#include "Qt3DSRenderUIPLoader.h" -#include "Qt3DSDMMetaData.h" -#include "Qt3DSRenderUIPSharedTranslation.h" - -#include <QtQml/qqmlengine.h> -#include <QtQml/qqmlcontext.h> -#include <QtQml/qqmlcomponent.h> -#include <QtQml/qjsengine.h> -#include <QtCore/qnumeric.h> -#include <QtCore/qfileinfo.h> - -//============================================================================== -// Namespace -//============================================================================== -namespace Q3DStudio { - -#if defined(_DEBUG) || (_PROFILE) -#define Q3DStudio_LOG_EVENT(S) // something -#else -#define Q3DStudio_LOG_EVENT(S) -#endif - -using qt3ds::runtime::IApplication; -using namespace qt3ds; - -namespace __SQmlEngineImpl_Basic_Structs__ { - struct QmlScopedLock - { - qt3ds::foundation::Mutex *m_Mutex; - - QmlScopedLock(qt3ds::foundation::Mutex *mtx) - : m_Mutex(mtx) - { - if (m_Mutex) - m_Mutex->lock(); - } - - ~QmlScopedLock() - { - if (m_Mutex) - m_Mutex->unlock(); - } - }; -} - -using namespace __SQmlEngineImpl_Basic_Structs__; -#define QML_ENGINE_MULTITHREAD_PROTECT_METHOD QmlScopedLock __locker(m_MultithreadedMutex); - -//============================================================================== -// Callback handling -/** -* Constructor -*/ -CScriptCallbacks::CScriptCallbacks() - : m_CallbackList(0, 0, "CallbackList") -{ -} - -/** -* Destructor -*/ -CScriptCallbacks::~CScriptCallbacks() -{ - FOR_ARRAY(SFrameCallbackEntry *, theEntry, m_CallbackList) - Q3DStudio_delete(*theEntry, SFrameCallbackEntry); - - m_CallbackList.Clear(); -} - -bool CScriptCallbacks::RegisterCallback(Q3DStudio::UINT32 callbackType, - const TScriptCallback inCallback, void *inUserData) -{ - // currently we only support these two types of callbacks - if (callbackType != SCRIPT_ON_INITIALIZE && callbackType != SCRIPT_ON_UPDATE) { - return false; - } - - SFrameCallbackEntry *theFrameCallbackEntry = NULL; - - try { - // note we don't care if someone registers the same function twice. - theFrameCallbackEntry = Q3DStudio_new(SFrameCallbackEntry) SFrameCallbackEntry(); - - if (!theFrameCallbackEntry) { - throw "failed to allocated SFrameCallbackEntry"; - } - - SScriptCallbackEntry *theScriptCallbackEntry = - Q3DStudio_new(SScriptCallbackEntry) SScriptCallbackEntry(); - if (!theScriptCallbackEntry) { - throw "failed to allocated SScriptCallbackEntry"; - } - - theScriptCallbackEntry->m_CallbackType = callbackType; - theScriptCallbackEntry->m_Function = inCallback; - theScriptCallbackEntry->m_UserData = inUserData; - theScriptCallbackEntry->m_Processed = false; - - theFrameCallbackEntry->m_Callbacks.Push(theScriptCallbackEntry); - - m_CallbackList.Push(theFrameCallbackEntry); - - } catch (const char *) { - if (theFrameCallbackEntry) - Q3DStudio_delete(theFrameCallbackEntry, SFrameCallbackEntry); - - return false; - } - - return true; -} - -void CScriptCallbacks::UnregisterCallback(Q3DStudio::UINT32, const TScriptCallback) -{ - // not used so far -} - -void CScriptCallbacks::ProcessCallbacks() -{ - // Call onInitialize function - FOR_ARRAY(SFrameCallbackEntry *, theFrameEntry, m_CallbackList) - { - FOR_ARRAY(SScriptCallbackEntry *, theEntry, (*theFrameEntry)->m_Callbacks) - { - if (((*theEntry)->m_CallbackType == SCRIPT_ON_INITIALIZE) && !(*theEntry)->m_Processed - && (*theEntry)->m_Function) { - (*theEntry)->m_Function((*theEntry)->m_UserData); - (*theEntry)->m_Processed = true; - } - } - } - - // Call onUpdate functions - FOR_ARRAY(SFrameCallbackEntry *, theFrameEntry, m_CallbackList) - { - FOR_ARRAY(SScriptCallbackEntry *, theEntry, (*theFrameEntry)->m_Callbacks) - { - // int type = (*theEntry)->m_CallbackType; - if ((*theEntry)->m_CallbackType == SCRIPT_ON_UPDATE && (*theEntry)->m_Function) { - (*theEntry)->m_Function((*theEntry)->m_UserData); - } - } - } -} - -//============================================================================== -//* End of helper class handling element operations -//============================================================================== - -//============================================================================== -/** -* Helper class handling command operations -*/ -class CQmlCommandHelper -{ - //============================================================================== - // Methods - //============================================================================== -private: // Constructors - CQmlCommandHelper(); - virtual ~CQmlCommandHelper(); - -public: // static Functions - static bool SetupGotoSlideCommand(TElement &inElement, const char *slideName, - const SScriptEngineGotoSlideArgs &inArgs); - static bool SetupGotoSlideCommand(TElement &inElement, Q3DStudio::INT32 inSlideIndex, - const SScriptEngineGotoSlideArgs &inArgs); - -protected: // Static Hidden Helpers - // static TElement* FireCommand(TEventCommandHash inCommand); - -public: // Static Helpers - static TElement *GetComponentParent(TElement *inParent); -}; - -//============================================================================== -/** -* Constructor -*/ -CQmlCommandHelper::CQmlCommandHelper() -{ -} - -//============================================================================== -/** -* Destructor -*/ -CQmlCommandHelper::~CQmlCommandHelper() -{ -} - -static Option<Q3DStudio::UINT8> FindSlide(TElement &inElement, const char *slideName) -{ - IPresentation *thePresentation = inElement.GetBelongedPresentation(); - - int theSlideHashName = thePresentation->GetApplication().HashString(slideName); - TComponent *theComponent = thePresentation->GetComponentManager().GetComponent(&inElement); - UINT8 theSlideIndex = - thePresentation->GetSlideSystem().FindSlide(*theComponent, theSlideHashName); - if (theSlideIndex >= theComponent->GetSlideCount()) { - qt3ds::foundation::CRegisteredString elemPath = thePresentation->GetElementPath(inElement); - if (elemPath.IsValid()) { - qCCritical(qt3ds::INVALID_OPERATION) - << "QMLCommandHelper: goToSlide: Unable to find slide " - << slideName <<"on element " << elemPath.c_str(); - } else { - qCCritical(qt3ds::INVALID_OPERATION) - << "QMLCommandHelper: goToSlide: Unable to find slide " - << slideName; - } - return Empty(); - } - - return theSlideIndex; -} - -TElement *CQmlCommandHelper::GetComponentParent(TElement *inElement) -{ - Q3DStudio_ASSERT(inElement); - return &inElement->GetComponentParent(); -} - -bool CQmlCommandHelper::SetupGotoSlideCommand(TElement &inElement, Q3DStudio::INT32 inSlideIndex, - const SScriptEngineGotoSlideArgs &inArgs) -{ - IPresentation *thePresentation = inElement.GetBelongedPresentation(); - TElement *theTarget = GetComponentParent(&inElement); - SComponentGotoSlideData theSlideData(inSlideIndex); - theSlideData.m_Mode = inArgs.m_Mode; - theSlideData.m_Paused = inArgs.m_Paused; - theSlideData.m_Rate = inArgs.m_Rate; - theSlideData.m_Reverse = inArgs.m_Reverse; - theSlideData.m_StartTime = inArgs.m_StartTime; - // Resolve playthroughto if it has a valid value. - if (!isTrivial(inArgs.m_PlaythroughTo)) { - if (AreEqual(inArgs.m_PlaythroughTo, "next")) - theSlideData.m_PlaythroughTo = -1; - else if (AreEqual(inArgs.m_PlaythroughTo, "previous")) - theSlideData.m_PlaythroughTo = -2; - else { - // Find the slide if possible. If not, then just error leave things as they are. - - Option<UINT8> theSlideIndex = FindSlide(inElement, inArgs.m_PlaythroughTo); - if (theSlideIndex.hasValue()) - theSlideData.m_PlaythroughTo = *theSlideIndex; - } - } - thePresentation->GetComponentManager().SetupComponentGotoSlideCommand(theTarget, theSlideData); - UVariant theArg1; - UVariant theArg2; - qt3ds::intrinsics::memZero(&theArg1, sizeof(UVariant)); - qt3ds::intrinsics::memZero(&theArg2, sizeof(UVariant)); - thePresentation->FireCommand(COMMAND_GOTOSLIDE, theTarget, &theArg1, &theArg2); - return true; -} - -bool CQmlCommandHelper::SetupGotoSlideCommand(TElement &inElement, const char *slideName, - const SScriptEngineGotoSlideArgs &inArgs) -{ - Option<UINT8> theSlideIndex = FindSlide(inElement, slideName); - if (theSlideIndex.hasValue()) - return SetupGotoSlideCommand(inElement, *theSlideIndex, inArgs); - - return false; -} - -//============================================================================== -//* End of helper class handling command operations -//============================================================================== - -struct SEmitSignalData : public NVRefCounted -{ - NVAllocatorCallback &m_Alloc; - volatile QT3DSI32 mRefCount; - INT32 m_SignalNameHandler; ///< The name of the signal to emit - TElement *m_TargetElement; ///< The source element where the event is going to occur - - SEmitSignalData(NVAllocatorCallback &alloc, INT32 inSignalName, TElement *inElement) - : m_Alloc(alloc) - , mRefCount(0) - , m_SignalNameHandler(inSignalName) - , m_TargetElement(inElement) - { - } - - QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Alloc) -}; - -class CQmlEngineImpl : public CQmlEngine -{ - using TEmitSignalPtr = NVScopedRefCounted<SEmitSignalData>; - using TEmitSignalQueue = eastl::list<TEmitSignalPtr, ForwardingAllocator>; - using TPropertyDescAndValueList = eastl::vector<qt3ds::runtime::element::TPropertyDescAndValue>; - using TPropertyDesc = qt3ds::runtime::element::SPropertyDesc; - - static const int MAX_ACTION_QUEUE_SIZE = 100; - -private: - qt3ds::NVFoundationBase &m_Foundation; - IApplication *m_Application; - IApplication *m_ApplicationCore; - qt3ds::foundation::Mutex m_PreloadMutex; - qt3ds::foundation::Mutex *m_MultithreadedMutex; - - TEmitSignalQueue m_EmitSignalDataList; - - QT3DSI32 mRefCount; - - CScriptCallbacks m_ScriptCallbacks; - - QQmlEngine m_engine; - QMap<QString, QQmlComponent *> m_components; - QVector<Q3DSQmlScript *> m_scripts; - -public: - CQmlEngineImpl(NVFoundationBase &fnd, ITimeProvider &inTimeProvider); - - QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation.getAllocator()) - - // functions from IScriptBridge - void EnableMultithreadedAccess() override; - void DisableMultithreadedAccess() override; - - void SetApplicationCore(qt3ds::runtime::IApplication &inApplication) override; - void SetApplication(qt3ds::runtime::IApplication &inApplication) override; - qt3ds::runtime::IApplication *GetApplication() override; - void Initialize() override; - - void LoadScript(IPresentation *presentation, TElement *element, const CHAR *path) override; - Q3DStudio::INT32 InitializeApplicationBehavior(const char *) override - { - return -1; - } - - void ProcessFrameCallbacks(IPresentation *) override; - void ExecuteApplicationScriptFunction(Q3DStudio::INT32, const char *) override {} - void CallFunction(const char *, const char *, - CScriptEngineCallFunctionArgRetriever &) override {} - - void ProcessSignal(IPresentation *inPresentation, - const SEventCommand &inCommand) override; - void ProcessCustomActions(IPresentation *inPresentation, - const SEventCommand &inCommand) override; - void ProcessCustomCallback(IPresentation *, const SEventCommand &) override {} - - void SetTableForElement(TElement &, IScriptTableProvider &) override {} - void SetAttribute(TElement *target, const char *attName, const char *value) override; - void SetAttribute(const char *element, const char *attName, const char *value) override; - bool GetAttribute(TElement *target, const char *attName, char *value) override; - bool GetAttribute(const char *element, const char *attName, char *value) override; - void FireEvent(const char *element, const char *evtName) override; - void SetDataInputValue(const QString &name, const QVariant &value, - qt3ds::runtime::DataInputValueRole valueRole) override; - void createElements(const QString &parentElementPath, const QString &slideName, - const QVector<QHash<QString, QVariant>> &properties, - qt3ds::render::IQt3DSRenderer *renderer) override; - void deleteElements(const QStringList &elementPaths, - qt3ds::render::IQt3DSRenderer *renderer) override; - void createMaterials(const QString &subPresId, const QStringList &materialDefinitions, - qt3ds::render::ICustomMaterialSystem *customMaterialSystem, - IDynamicObjectSystem *dynamicObjectSystem, - qt3ds::render::IQt3DSRenderer *renderer) override; - void deleteMaterials(const QStringList &materialNames, - qt3ds::render::IQt3DSRenderer *renderer) override; - void createMesh(const QString &name, qt3dsimp::Mesh *mesh, - qt3ds::render::IBufferManager *bufferManager) override; - void deleteMeshes(const QStringList &meshNames, - qt3ds::render::IBufferManager *bufferManager) override; - - void GotoSlide(const char *component, const char *slideName, - const SScriptEngineGotoSlideArgs &inArgs) override; - void GotoSlideRelative(const char *, bool, bool, const SScriptEngineGotoSlideArgs &) override; - - void SetPresentationAttribute(const char *, const char *, const char *) override; - - // No need to implement here, as sound playing is done in Qt3DSViewerApp - bool PlaySoundFile(const char *) override { return false; } - - void EnableDebugging(qt3ds::state::debugger::IMultiProtocolSocket &) override {} - void EnableProfiling() override {} - void StepGC() override {} - - // functions from CQMLEngine - bool PeekSignal(TElement *&outElement, char *&outName) override; - void GotoSlideIndex(const char *component, const Q3DStudio::INT32 slideIndex, - const SScriptEngineGotoSlideArgs &inArgs) override; - bool GetSlideInfo(const char *elementPath, int ¤tIndex, int &previousIndex, - QString ¤tName, QString &previousName) override; - void GotoTime(const char *component, const Q3DStudio::FLOAT time) override; - bool RegisterCallback(Q3DStudio::UINT32 callbackType, const TScriptCallback inCallback, - void *inUserData) override; - void Shutdown(qt3ds::NVFoundationBase &inFoundation) override; - -private: - TElement *createMaterialContainer(TElement *parent, CPresentation *presentation); - void createComponent(QQmlComponent *component, TElement *element); - TElement *getTarget(const char *component); - void listAllElements(TElement *root, QList<TElement *> &elements); - void initializeDataInputsInPresentation(CPresentation &presentation, bool isPrimary, - QList<TElement *> inElements = QList<TElement *>()); - void initializeDataOutputsInPresentation(CPresentation &presentation, bool isPrimary); - // Splits down vector attributes to components as Runtime does not really - // handle vectors at this level anymore - bool getAttributeVector3(QVector<QByteArray> &outAttVec, const QByteArray &attName, - TElement *elem); - bool getAttributeVector2(QVector<QByteArray> &outAttVec, const QByteArray &attName, - TElement *elem); - // build and evaluate Evaluator datainput type expression - QJSValue buildJSFunc(const QString &userFunc); - // pass controller name for error reporting purposes - QVariant callJSFunc(const QString &controllerName, qt3ds::runtime::DataInputDef &diDef, - const QVariant::Type type); - // matches all numeric datatypes so we do not get datatype mismatch when JS - // decides to change result datatype (f.ex from double to int when result - // fractional part for specific input values happens to be exactly zero) - bool isMatchingDatatype(QVariant::Type resultType, QVariant::Type propertyType); - // find out which datainputs are used in the expression - QVector<QString> resolveDependentDatainputs(const QString &expression, - const QString &controllerName); - - // Methods to add element attributes to list for element creation - void addStringAttribute(qt3ds::foundation::IStringTable &strTable, - TPropertyDescAndValueList &list, - const QString &inAttName, const QString &inValue); - void addIntAttribute(qt3ds::foundation::IStringTable &strTable, - TPropertyDescAndValueList &list, - const QString &inAttName, int inValue); - void addBoolAttribute(qt3ds::foundation::IStringTable &strTable, - TPropertyDescAndValueList &list, - const QString &inAttName, bool inValue); - void addFloatAttribute(qt3ds::foundation::IStringTable &strTable, - TPropertyDescAndValueList &list, - const QString &inAttName, float inValue); - void addFloat2Attribute(qt3ds::foundation::IStringTable &strTable, - TPropertyDescAndValueList &list, - const QStringList &inAttNames, const QVector2D &inValue); - void addFloat3Attribute(qt3ds::foundation::IStringTable &strTable, - TPropertyDescAndValueList &list, - const QStringList &inAttNames, const QVector3D &inValue); - void addFloat4Attribute(qt3ds::foundation::IStringTable &strTable, - TPropertyDescAndValueList &list, - const QStringList &inAttNames, const QVector4D &inValue); - void addElementRefAttribute(qt3ds::foundation::IStringTable &strTable, - TPropertyDescAndValueList &list, - const QString &inAttName, TElement *element); - template <typename TDataType> - void setDynamicObjectProperty(qt3ds::render::SDynamicObject &material, - const qt3ds::render::dynamic::SPropertyDefinition &propDesc, - const TDataType &propValue); - QVector2D parseFloat2Property(const QString &propValue); - QVector3D parseFloat3Property(const QString &propValue); - QVector4D parseFloat4Property(const QString &propValue); - - void notifyElementCreation(const QStringList &elementNames, const QString &error); - void notifyMaterialCreation(const QStringList &materialNames, const QString &error); - void deleteElements(const QVector<TElement *> &elements, - qt3ds::render::IQt3DSRenderer *renderer); -}; - -CQmlEngineImpl::CQmlEngineImpl(NVFoundationBase &fnd, ITimeProvider &) - : m_Foundation(fnd) - , m_Application(NULL) - , m_ApplicationCore(NULL) - , m_PreloadMutex(fnd.getAllocator()) - , m_MultithreadedMutex(NULL) - , m_EmitSignalDataList( - ForwardingAllocator(fnd.getAllocator(), "CQmlEngineImpl::m_EmitSignalDataList")) - , mRefCount(0) -{ - qmlRegisterType<Q3DSQmlBehavior>("QtStudio3D.Behavior", 1, 0, "Behavior"); - qmlRegisterType<Q3DSQmlBehavior, 1>("QtStudio3D.Behavior", 1, 1, "Behavior"); -} - -void CQmlEngineImpl::Shutdown(qt3ds::NVFoundationBase &inFoundation) -{ -} - -void CQmlEngineImpl::EnableMultithreadedAccess() -{ - m_MultithreadedMutex = &m_PreloadMutex; -} - -void CQmlEngineImpl::DisableMultithreadedAccess() -{ - m_MultithreadedMutex = NULL; -} - -void CQmlEngineImpl::SetApplicationCore(runtime::IApplication &inApplication) -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - m_ApplicationCore = &inApplication; -} - -void CQmlEngineImpl::SetApplication(qt3ds::runtime::IApplication &inApplication) -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - m_Application = &inApplication; -} - -qt3ds::runtime::IApplication *CQmlEngineImpl::GetApplication() -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - return m_Application; -} - -void CQmlEngineImpl::Initialize() -{ - // Gather data input controlled properties - QList<CPresentation *> presentations = m_Application->GetPresentationList(); - - for (int i = 0; i < presentations.size(); ++i) { - initializeDataInputsInPresentation(*presentations[i], i == 0); - initializeDataOutputsInPresentation(*presentations[i], i == 0); - } -} - -void CQmlEngineImpl::SetAttribute(TElement *target, const char *attName, const char *value) -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - if (target) { - bool success = CQmlElementHelper::SetAttribute(target, attName, value, false); - if (!success) { - qCCritical(qt3ds::INVALID_OPERATION) - << "CQmlEngineImpl::SetAttribute: " - << "failed to set attribute on element" - << target << ":" << attName << ":" << value; - } - } -} - -void CQmlEngineImpl::SetAttribute(const char *element, const char *attName, const char *value) -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - - TElement *theTarget = getTarget(element); - if (theTarget) { - bool success = CQmlElementHelper::SetAttribute(theTarget, attName, value, false); - if (!success) { - qCCritical(qt3ds::INVALID_OPERATION) - << "CQmlEngineImpl::SetAttribute: " - << "failed to set attribute on element" - << element << ":" << attName << ":" << value; - } - } -} - -bool CQmlEngineImpl::GetAttribute(TElement *target, const char *attName, char *value) -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - - if (target) { - bool success = CQmlElementHelper::GetAttribute(target, attName, value); - if (!success) { - qCCritical(qt3ds::INVALID_OPERATION) - << "CQmlEngineImpl::GetAttribute: " - << "failed to get attribute on element" - << target << ":" << attName << ":" << value; - } - return success; - } - - return false; -} - -bool CQmlEngineImpl::GetAttribute(const char *element, const char *attName, char *value) -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - - TElement *theTarget = getTarget(element); - if (theTarget) { - bool success = CQmlElementHelper::GetAttribute(theTarget, attName, value); - if (!success) { - qCCritical(qt3ds::INVALID_OPERATION) - << "CQmlEngineImpl::GetAttribute: " - << "failed to get attribute on element" - << element << ":" << attName << ":" << value; - } - return success; - } - - return false; -} - -void CQmlEngineImpl::LoadScript(IPresentation *presentation, TElement *element, const CHAR *path) -{ - QString presPath = QFileInfo(presentation->GetFilePath()).absolutePath(); - - QString sourcePath(presPath + QLatin1Char('/') + path); - sourcePath.replace(QLatin1Char('\\'), QLatin1Char('/')); - - TElement *parent = element->GetParent(); - if (!parent) - return; - - if (!m_components.contains(sourcePath)) { - m_components[sourcePath] = new QQmlComponent(&m_engine, QUrl::fromLocalFile(sourcePath), - &m_engine); - } - - QQmlComponent *component = m_components[sourcePath]; - if (component->status() == QQmlComponent::Ready) { - createComponent(component, element); - } else if (component->status() == QQmlComponent::Error) { - qWarning() << "Error while loading script" - << component->url().toString() - << ":" << component->errorString(); - } else { - QObject::connect(component, &QQmlComponent::statusChanged, - [this, component, element] (QQmlComponent::Status status) { - if (status == QQmlComponent::Ready) { - createComponent(component, element); - } else { - qWarning() << "Error while loading script" - << component->url().toString() - << ":" << component->errorString(); - } - } - ); - } -} - -void CQmlEngineImpl::FireEvent(const char *element, const char *evtName) -{ - TElement *theElement = getTarget(element); - if (theElement && theElement->GetActive() == true) { - IPresentation *thePresentation = theElement->GetBelongedPresentation(); - thePresentation->FireEvent(CHash::HashEventCommand(evtName), theElement); - } else { - qCCritical(qt3ds::INVALID_OPERATION) - << "CQmlEngineImpl::FireEvent: " - << "failed to find element: " - << element << " " << evtName; - } -} - -void CQmlEngineImpl::SetDataInputValue( - const QString &name, const QVariant &value, - qt3ds::runtime::DataInputValueRole valueRole = qt3ds::runtime::DataInputValueRole::Value) -{ - qt3ds::runtime::DataInputMap &diMap = m_Application->dataInputMap(); - if (diMap.contains(name)) { - qt3ds::runtime::DataInputDef &diDef = diMap[name]; - switch (valueRole) { - case qt3ds::runtime::DataInputValueRole::Value: { // switch (valueRole) - diDef.value = value; - const QVector<qt3ds::runtime::DataInOutAttribute> &ctrlAtt - = diDef.controlledAttributes; - for (const qt3ds::runtime::DataInOutAttribute &ctrlElem : ctrlAtt) { - switch (ctrlElem.propertyType) { - case ATTRIBUTETYPE_DATAINPUT_TIMELINE: { - // Quietly ignore other than number type data inputs when adjusting timeline - if (diDef.type == qt3ds::runtime::DataInOutTypeRangedNumber) { - TTimeUnit endTime = 0; - TElement *element = getTarget(ctrlElem.elementPath.constData()); - TComponent *component = static_cast<TComponent *>(element); - endTime = component->GetTimePolicy().GetLoopingDuration(); - - // Normalize the value to dataInput range - qreal newTime = qreal(endTime) * (qreal(value.toFloat() - diDef.min) - / qreal(diDef.max - diDef.min)); - GotoTime(ctrlElem.elementPath.constData(), float(newTime / 1000.0)); - } - break; - } - case ATTRIBUTETYPE_DATAINPUT_SLIDE: { - // Quietly ignore other than string type when adjusting slide - if (diDef.type == qt3ds::runtime::DataInOutTypeString) { - const QByteArray valueStr = value.toString().toUtf8(); - GotoSlide(ctrlElem.elementPath.constData(), valueStr.constData(), - SScriptEngineGotoSlideArgs()); - } - break; - } - // Silently ignore invalid incoming type if it does not - // match with the datainput type except with type Variant, for which - // the incoming value is cast to target property type without checking. - // Caveat emptor. - - // For Evaluator, typecheck the JS evaluation result to see if it - // matches with the target property. - - // Handle ranged number similarly to generic float - // if it is bound to properties other - // than timeline animation i.e. disregard range min and max - case ATTRIBUTETYPE_FLOAT: { - float valueFloat; - if (diDef.type == qt3ds::runtime::DataInOutTypeFloat - || diDef.type == qt3ds::runtime::DataInOutTypeRangedNumber - || diDef.type == qt3ds::runtime::DataInOutTypeVariant) { - valueFloat = value.toFloat(); - } else if (diDef.type == qt3ds::runtime::DataInOutTypeEvaluator) { - valueFloat = callJSFunc(name, diDef, QVariant::Type::Double).toFloat(); - } else { - qWarning() << __FUNCTION__ << "Property type " - << ctrlElem.propertyType - << " not matching with Datainput " << name - << " data type " - << diDef.type; - break; - } - - SetAttribute(ctrlElem.elementPath.constData(), - ctrlElem.attributeName.first().constData(), - reinterpret_cast<const char *>(&valueFloat)); - break; - } - case ATTRIBUTETYPE_FLOAT4: { - QVector4D valueVec; - if (diDef.type == qt3ds::runtime::DataInOutTypeVector4) { - valueVec = value.value<QVector4D>(); - } else { - qWarning() << __FUNCTION__ << "Property type " - << ctrlElem.propertyType - << " not matching with Datainput " << name - << " data type " - << diDef.type; - break; - } - // Set the values of vector attribute components separately - for (int i = 0; i < 4; i++) { - const float val = valueVec[i]; - SetAttribute(ctrlElem.elementPath.constData(), - ctrlElem.attributeName[i].constData(), - reinterpret_cast<const char *>(&val)); - } - break; - } - case ATTRIBUTETYPE_FLOAT3: { - QVector3D valueVec; - if (diDef.type == qt3ds::runtime::DataInOutTypeVector3 - || diDef.type == qt3ds::runtime::DataInOutTypeVariant) { - valueVec = value.value<QVector3D>(); - } else if (diDef.type == qt3ds::runtime::DataInOutTypeEvaluator) { - const QVariant res = callJSFunc(name, diDef, QVariant::Type::Vector3D); - valueVec = res.value<QVector3D>(); - } else { - qWarning() << __FUNCTION__ << "Property type " - << ctrlElem.propertyType - << " not matching with Datainput " << name - << " data type " - << diDef.type; - break; - } - // Set the values of vector attribute components separately - for (int i = 0; i < 3; i++) { - const float val = valueVec[i]; - SetAttribute(ctrlElem.elementPath.constData(), - ctrlElem.attributeName[i].constData(), - reinterpret_cast<const char *>(&val)); - } - break; - } - case ATTRIBUTETYPE_FLOAT2: - { - QVector2D valueVec; - if (diDef.type == qt3ds::runtime::DataInOutTypeVector2 - || diDef.type == qt3ds::runtime::DataInOutTypeVariant) { - valueVec = value.value<QVector2D>(); - } else if (diDef.type == qt3ds::runtime::DataInOutTypeEvaluator) { - const QVariant res = callJSFunc(name, diDef, QVariant::Type::Vector2D); - valueVec = res.value<QVector2D>(); - } else { - qWarning() << __FUNCTION__ << "Property type " - << ctrlElem.propertyType - << " not matching with Datainput " << name - << " data type " - << diDef.type; - break; - } - // Set the values of vector attribute components separately - for (int i = 0; i < 2; i++) { - const float val = valueVec[i]; - SetAttribute(ctrlElem.elementPath.constData(), - ctrlElem.attributeName[i].constData(), - reinterpret_cast<const char *>(&val)); - } - break; - } - case ATTRIBUTETYPE_BOOL: { - uint valueBool; // SetAttribute requires at least 32-bit variable - if (diDef.type == qt3ds::runtime::DataInOutTypeBoolean - || diDef.type == qt3ds::runtime::DataInOutTypeVariant) { - valueBool = value.toBool(); - } else if (diDef.type == qt3ds::runtime::DataInOutTypeEvaluator) { - valueBool = callJSFunc(name, diDef, QVariant::Type::Bool).toBool(); - } else { - qWarning() << __FUNCTION__ << "Property type " - << ctrlElem.propertyType - << " not matching with Datainput " << name - << " data type " - << diDef.type; - break; - } - - SetAttribute(ctrlElem.elementPath.constData(), - ctrlElem.attributeName.first().constData(), - reinterpret_cast<const char *>(&valueBool)); - break; - } - case ATTRIBUTETYPE_STRING: { - QByteArray valueStr; - // Allow scalar number types also as inputs to string attribute - if (diDef.type == qt3ds::runtime::DataInOutTypeString - || diDef.type == qt3ds::runtime::DataInOutTypeRangedNumber - || diDef.type == qt3ds::runtime::DataInOutTypeFloat - || diDef.type == qt3ds::runtime::DataInOutTypeVariant) { - valueStr = value.toString().toUtf8(); - } else if (diDef.type == qt3ds::runtime::DataInOutTypeEvaluator) { - valueStr = callJSFunc(name, diDef, QVariant::Type::String) - .toString().toUtf8(); - } else { - qWarning() << __FUNCTION__ << "Property type " - << ctrlElem.propertyType - << " not matching with Datainput " << name - << " data type " - << diDef.type; - break; - } - - SetAttribute(ctrlElem.elementPath.constData(), - ctrlElem.attributeName.first().constData(), - valueStr.constData()); - break; - } - default: - QT3DS_ALWAYS_ASSERT_MESSAGE("Unexpected data input type"); - break; - } - } - - // Trigger re-evaluation of Evaluator datainputs that use this datainput - // as source data. Do this by calling setDataInputValue for evaluator - // with the current set value of the Evaluator (_not_ the evaluator result) - for (auto dependent : diDef.dependents) { - // Dependent list also contains the name of this datainput if - // the value of this datainput is used as source data. In this case - // obviously do not cause infinite recursion. - if (dependent != name) - SetDataInputValue(dependent, diMap[dependent].value); - } - break; - } - case qt3ds::runtime::DataInputValueRole::Max: { // switch (valueRole) - diDef.max = value.toFloat(); - break; - } - case qt3ds::runtime::DataInputValueRole::Min: { // switch (valueRole) - diDef.min = value.toFloat(); - break; - } - } - } -} - -static int _idCounter = 0; - -void CQmlEngineImpl::createElements(const QString &parentElementPath, const QString &slideName, - const QVector<QHash<QString, QVariant>> &properties, - qt3ds::render::IQt3DSRenderer *renderer) -{ - using namespace qt3ds::render; - - int elementIndex = -1; - QString error; - CPresentation *presentation = nullptr; - QStringList elementPaths; - elementPaths.reserve(properties.size()); - QVector<QHash<QString, QVariant>> theProperties = properties; - const QString namePropName = QStringLiteral("name"); - - for (int i = 0; i < theProperties.size(); ++i) { - auto &props = theProperties[i]; - QString newElementName = props.value(namePropName).toString(); - if (newElementName.isEmpty()) { - // The id number on generated name will match generated graph object identifiers - newElementName = QStringLiteral("NewElement_%1").arg(_idCounter + i + 1); - props.insert(namePropName, newElementName); - } - elementPaths << parentElementPath + QLatin1Char('.') + newElementName; - } - QVector<TElement *> createdElements; - TElement *parentElement = nullptr; - - auto handleError = [&]() { - if (!error.isEmpty()) - deleteElements(createdElements, renderer); - notifyElementCreation(elementPaths, error); - }; - - // Resolve parent element - QByteArray theParentPath = parentElementPath.toUtf8(); - parentElement = getTarget(theParentPath.constData()); - - if (!parentElement) { - error = QObject::tr("Invalid parent element: '%1'").arg(parentElementPath); - handleError(); - return; - } - - auto parentTranslator = static_cast<Qt3DSTranslator *>(parentElement->GetAssociation()); - - if (!parentTranslator || !GraphObjectTypes::IsNodeType( - parentTranslator->GetUIPType())) { - error = QObject::tr("Parent element is not a valid node: '%1'").arg(parentElementPath); - handleError(); - return; - } - - TElement &component = parentElement->GetComponentParent(); - auto &parentObject = static_cast<SNode &>(parentTranslator->RenderObject()); - presentation = static_cast<CPresentation *>(parentElement->GetBelongedPresentation()); - - // 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) { - error = QObject::tr("Invalid slide name for time context: '%1'").arg(slideName); - handleError(); - return; - } - - auto &strTable = presentation->GetStringTable(); - - const QString sourcePathPropName = QStringLiteral("sourcepath"); - 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); - const int parentStartTime = int(attValue.m_INT32); - parentElement->GetAttribute(Q3DStudio::ATTRIBUTE_ENDTIME, attValue); - const int parentEndTime = int(attValue.m_INT32); - - for (const auto ¤tProps : qAsConst(theProperties)) { - ++_idCounter; - ++elementIndex; - - // Remove properties requiring custom handling - QHash<QString, QVariant> fixedProps = currentProps; - QString newElementName = fixedProps.take(namePropName).toString(); - QByteArray newElementNameBa = newElementName.toUtf8(); - - QString refMatName = fixedProps.take(QStringLiteral("material")).toString(); - int colonIndex = refMatName.indexOf(QLatin1Char(':')); - if (colonIndex != -1) - refMatName = refMatName.mid(colonIndex + 1); - if (refMatName.startsWith(QLatin1Char('#'))) // Absolute reference - refMatName = refMatName.mid(1); - else if (!refMatName.isEmpty() && !refMatName.contains(QLatin1Char('/'))) - refMatName = QStringLiteral("/") + refMatName; - - // Make sure the name is not duplicate - TElement *existingChild - = parentElement->FindChild(CHash::HashString(newElementNameBa.constData())); - if (existingChild) { - error = QObject::tr("Element already exists: '%1'").arg(elementPaths[elementIndex]); - handleError(); - return; - } - - const CRegisteredString regName = strTable.RegisterStr(newElementNameBa); - TPropertyDescAndValueList elementProperties; - CRegisteredString metaType; - const CRegisteredString elementSubType; - GraphObjectTypes::Enum objectType = GraphObjectTypes::Unknown; - - QString typeStr = fixedProps.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; - fixedProps.value(eyeBallPropName, true).toBool(); - if (objectType == GraphObjectTypes::Model && !fixedProps.contains(sourcePathPropName)) { - addStringAttribute(strTable, elementProperties, sourcePathPropName, - QStringLiteral("#Cube")); - } - if (!fixedProps.contains(startTimePropName)) - addIntAttribute(strTable, elementProperties, startTimePropName, parentStartTime); - if (!fixedProps.contains(endTimePropName)) - addIntAttribute(strTable, elementProperties, endTimePropName, parentEndTime); - if (!fixedProps.contains(eyeBallPropName)) - addBoolAttribute(strTable, elementProperties, eyeBallPropName, true); - else - eyeBall = fixedProps.value(eyeBallPropName).toBool(); - - QHashIterator<QString, QVariant> it(fixedProps); - while (it.hasNext()) { - it.next(); - switch (it.value().type()) { - case QVariant::Double: - addFloatAttribute(strTable, elementProperties, it.key(), it.value().toFloat()); - break; - case QVariant::Bool: - addBoolAttribute(strTable, elementProperties, it.key(), it.value().toBool()); - break; - case QVariant::Int: - addIntAttribute(strTable, elementProperties, it.key(), it.value().toInt()); - break; - case QVariant::String: - addStringAttribute(strTable, 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(strTable, elementProperties, atts, vec); - break; - } - default: - error = QObject::tr("Unsupported property type for: '%1'").arg(it.key()); - handleError(); - return; - } - } - - // Create new element - QString localElementPath = elementPaths[elementIndex]; - colonIndex = localElementPath.indexOf(QLatin1Char(':')); - if (colonIndex != -1) - localElementPath = localElementPath.mid(colonIndex + 1); - TElement &newElem = m_Application->GetElementAllocator().CreateElement( - regName, metaType, elementSubType, - toConstDataRef(elementProperties.data(), QT3DSU32(elementProperties.size())), - presentation, parentElement, false); - newElem.m_Path = strTable.RegisterStr(localElementPath); - - // Insert the new element into the correct slide - if (!slideSystem.addSlideElement(component, slideIndex, newElem, eyeBall)) { - // Delete created element if adding to slide failed - m_Application->GetElementAllocator().ReleaseElement(newElem, true); - error = QObject::tr("Failed to add the new element to a slide"); - handleError(); - return; - } - - SGraphObject *referencedMaterial = nullptr; - 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 = localElementPath + 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<Qt3DSTranslator *>( - nextChild->GetAssociation()); - referencedMaterial = static_cast<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<Qt3DSTranslator *>(firstChild->GetAssociation()); - referencedMaterial = static_cast<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. - 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(); - SModel *newObject = QT3DS_NEW(allocator, SModel)(); - newObject->m_Id = strTable.RegisterStr((QByteArrayLiteral("__newObj_") - + QByteArray::number(_idCounter)).constData()); - parentObject.AddChild(*newObject); - - Qt3DSTranslator::CreateTranslatorForElement(newElem, *newObject, allocator); - - 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; - 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); - - createdElements << &newElem; - } - - bool isPrimary = presentation == m_Application->GetPrimaryPresentation() ? true : false; - initializeDataInputsInPresentation(*presentation, isPrimary, createdElements.toList()); - - renderer->ChildrenUpdated(parentObject); - - handleError(); -} - -// Only supports deleting element types that can be added via createElement. -void CQmlEngineImpl::deleteElements(const QStringList &elementPaths, - qt3ds::render::IQt3DSRenderer *renderer) -{ - QVector<TElement *> elements; - // Convert the path list to set for quicker lookups - QSet<QString> pathSet = elementPaths.toSet(); - - for (auto &elementPath : elementPaths) { - // Check that parent is not already included in the deleted elements - int idx = elementPath.lastIndexOf(QLatin1Char('.')); - bool parentFound = false; - while (idx != -1) { - QString parentPath = elementPath.left(idx); - if (pathSet.contains(parentPath)) { - parentFound = true; - break; - } - idx = parentPath.lastIndexOf(QLatin1Char('.')); - } - if (!parentFound) { - // Resolve element - QByteArray thePath = elementPath.toUtf8(); - TElement *element = getTarget(thePath.constData()); - if (element) - elements << element; - } - } - deleteElements(elements, renderer); -} - -TElement *CQmlEngineImpl::createMaterialContainer(TElement *parent, CPresentation *presentation) -{ - TPropertyDescAndValueList prop; - auto &strTable = presentation->GetStringTable(); - const auto matName = strTable.RegisterStr(QStringLiteral("__Container")); - const auto matType = strTable.RegisterStr(QStringLiteral("Material")); - const auto matClass = CRegisteredString(); - TElement &element = m_Application->GetElementAllocator().CreateElement( - matName, matType, matClass, - toConstDataRef(prop.data(), prop.size()), - presentation, parent, false); - return &element; -} - -/** - Creates material into material container of the specified subpresentation. - The materialDefinition parameter can contain a .materialdef file path or - the entire material definition in the .materialdef format. -*/ -void CQmlEngineImpl::createMaterials(const QString &subPresId, - const QStringList &materialDefinitions, - ICustomMaterialSystem *customMaterialSystem, - IDynamicObjectSystem *dynamicObjectSystem, - qt3ds::render::IQt3DSRenderer *renderer) -{ - CPresentation *presentation = nullptr; - QString error; - QString presPath; - QString projPath; - struct MaterialInfo { - QString materialDefinition; - QString materialName; - QMap<QString, QString> materialProps; - QMap<QString, QMap<QString, QString>> textureProps; - }; - QVector<MaterialInfo *> materialInfos; - QVector<TElement *> createdElements; - - auto handleError = [&]() { - if (!error.isEmpty()) - deleteElements(createdElements, renderer); - QStringList materialNames; - QString prefix; - if (!subPresId.isEmpty()) - prefix = subPresId + QLatin1Char(':'); - for (auto &materialInfo : materialInfos) - materialNames << prefix + materialInfo->materialName; - qDeleteAll(materialInfos); - notifyMaterialCreation(materialNames, error); - }; - - auto getMaterialInfos = [&]() { - for (auto &materialDefinition : materialDefinitions) { - MaterialInfo *info = new MaterialInfo; - info->materialDefinition = materialDefinition; - Q3DSMaterialDefinitionParser::getMaterialInfo(materialDefinition, projPath, presPath, - info->materialName, info->materialProps, - info->textureProps); - materialInfos << info; - } - }; - - QByteArray theSubPresId = subPresId.toUtf8(); - if (theSubPresId.isEmpty()) - presentation = m_Application->GetPrimaryPresentation(); - else - presentation = m_Application->GetPresentationById(theSubPresId.constData()); - - if (!presentation) { - error = QObject::tr("Invalid presentation ID: '%1'").arg(subPresId); - presentation = m_Application->GetPrimaryPresentation(); - presPath = QFileInfo(presentation->GetFilePath()).absolutePath(); - projPath = presentation->getProjectPath(); - getMaterialInfos(); - handleError(); - return; - } - - presPath = QFileInfo(presentation->GetFilePath()).absolutePath(); - projPath = presentation->getProjectPath(); - getMaterialInfos(); - - // Find material container - auto &strTable = presentation->GetStringTable(); - NVAllocatorCallback &allocator = presentation->GetScene()->allocator(); - TElement *rootElement = presentation->GetRoot(); - const auto containerName = strTable.RegisterStr("__Container"); - TElement *container = rootElement->FindChild(CHash::HashString(containerName.c_str())); - if (!container) - container = createMaterialContainer(rootElement, presentation); - - for (auto &materialInfo : materialInfos) { - if (materialInfo->materialName.isEmpty() || materialInfo->materialProps.isEmpty()) { - error = QObject::tr("Invalid material definition: '%1'") - .arg(materialInfo->materialDefinition); - handleError(); - return; - } - - // We don't care about the path parameter - const QString pathStr = QStringLiteral("path"); - if (materialInfo->materialProps.contains(pathStr)) - materialInfo->materialProps.remove(pathStr); - - // Check that the material doesn't already exist in container - TElement *firstChild = nullptr; - TElement *nextChild = container->GetChild(); - firstChild = nextChild; - while (nextChild) { - QString childName = QString::fromUtf8(nextChild->m_Name); - if (childName == materialInfo->materialName) { - error = QObject::tr("Material already exists in material container"); - handleError(); - return; - } - nextChild = nextChild->GetSibling(); - } - - // Create material element in the container based on the material definition - auto &metaData = m_Application->GetMetaData(); - const auto matName = strTable.RegisterStr(materialInfo->materialName); - const bool isCustomMaterial = (materialInfo->materialProps.value(QStringLiteral("type")) - == QLatin1String("CustomMaterial")); - CRegisteredString matType; - CRegisteredString matClass; - QHash<QString, qt3ds::render::dynamic::SPropertyDefinition> dynPropDefs; - - if (isCustomMaterial) { - CRegisteredString sourcePath - = strTable.RegisterStr(materialInfo->materialProps.value( - QStringLiteral("sourcepath")).toUtf8()); - matType = strTable.RegisterStr("CustomMaterial"); - matClass = sourcePath; // Create just one class per shader - if (sourcePath.IsValid()) { - Option<qt3dsdm::SMetaDataCustomMaterial> matMetaData = - metaData.GetMaterialMetaDataBySourcePath(sourcePath.c_str()); - if (!matMetaData.hasValue()) { - metaData.LoadMaterialXMLFile(matType.c_str(), matClass.c_str(), matName.c_str(), - sourcePath.c_str()); - matMetaData = metaData.GetMaterialMetaDataBySourcePath(sourcePath.c_str()); - } - if (matMetaData.hasValue()) { - qt3ds::render::IUIPLoader::CreateMaterialClassFromMetaMaterial( - matClass, m_Foundation, *customMaterialSystem, matMetaData, - strTable); - NVConstDataRef<qt3ds::render::dynamic::SPropertyDefinition> customProperties; - customProperties = dynamicObjectSystem->GetProperties(matClass); - for (QT3DSU32 i = 0, end = customProperties.size(); i < end; ++i) { - QString propName = QString::fromUtf8(customProperties[i].m_Name.c_str()); - if (materialInfo->materialProps.contains(propName)) - dynPropDefs.insert(propName, customProperties[i]); - } - } else { - error = QObject::tr("Could not resolve properties for CustomMaterial"); - handleError(); - return; - } - } else { - error = QObject::tr("Missing sourcepath in definition of CustomMaterial"); - handleError(); - return; - } - } else { - matType = strTable.RegisterStr("Material"); - } - - auto createElementPropsFromDefProps = [&](const QMap<QString, QString> &defProps, - TPropertyDescAndValueList &elementProps, - const CRegisteredString &elementType) { - QMapIterator<QString, QString> propIter(defProps); - while (propIter.hasNext()) { - propIter.next(); - if (dynPropDefs.contains(propIter.key())) - continue; // Dynamic properties are added directly to graph objects later - - auto propName = strTable.RegisterStr(propIter.key()); - ERuntimeDataModelDataType dataType; - ERuntimeAdditionalMetaDataType additionalType; - dataType = metaData.GetPropertyType(elementType, propName); - additionalType = metaData.GetAdditionalType(elementType, propName); - - switch (dataType) { - case ERuntimeDataModelDataTypeLong: { - addIntAttribute(strTable, elementProps, propIter.key(), - propIter.value().toInt()); - break; - } - case ERuntimeDataModelDataTypeFloat: { - addFloatAttribute(strTable, elementProps, propIter.key(), - propIter.value().toFloat()); - break; - } - case ERuntimeDataModelDataTypeFloat2: { - QVector2D vec = parseFloat2Property(propIter.value()); - QStringList atts; - atts << (propIter.key() + QLatin1String(".x")) - << (propIter.key() + QLatin1String(".y")); - addFloat2Attribute(strTable, elementProps, atts, vec); - break; - } - case ERuntimeDataModelDataTypeFloat3: { - QVector3D vec = parseFloat3Property(propIter.value()); - if (additionalType == ERuntimeAdditionalMetaDataTypeRotation) { - vec.setX(qDegreesToRadians(vec.x())); - vec.setY(qDegreesToRadians(vec.y())); - vec.setZ(qDegreesToRadians(vec.z())); - } - QStringList atts; - atts << (propIter.key() + QLatin1String(".x")) - << (propIter.key() + QLatin1String(".y")) - << (propIter.key() + QLatin1String(".z")); - addFloat3Attribute(strTable, elementProps, atts, vec); - break; - } - case ERuntimeDataModelDataTypeFloat4: { - QVector4D vec = parseFloat4Property(propIter.value()); - QStringList atts; - if (additionalType == ERuntimeAdditionalMetaDataTypeColor) { - atts << (propIter.key() + QLatin1String(".r")) - << (propIter.key() + QLatin1String(".g")) - << (propIter.key() + QLatin1String(".b")) - << (propIter.key() + QLatin1String(".a")); - } else { - atts << (propIter.key() + QLatin1String(".x")) - << (propIter.key() + QLatin1String(".y")) - << (propIter.key() + QLatin1String(".z")) - << (propIter.key() + QLatin1String(".w")); - } - addFloat4Attribute(strTable, elementProps, atts, vec); - break; - } - case ERuntimeDataModelDataTypeBool: { - bool boolValue = propIter.value().compare(QLatin1String("true"), - Qt::CaseInsensitive) == 0; - addBoolAttribute(strTable, elementProps, propIter.key(), boolValue); - break; - } - case ERuntimeDataModelDataTypeStringRef: - case ERuntimeDataModelDataTypeString: { - addStringAttribute(strTable, elementProps, propIter.key(), propIter.value()); - break; - } - case ERuntimeDataModelDataTypeLong4: { - if (additionalType == ERuntimeAdditionalMetaDataTypeImage) { - // Insert placeholder for now, will be patched later - addElementRefAttribute(strTable, elementProps, propIter.key(), nullptr); - } - break; - } - default: - error = QObject::tr("Unsupported material property type for property: '%1'") - .arg(propIter.key()); - return; - } - } - }; - - TPropertyDescAndValueList elementProps; - createElementPropsFromDefProps(materialInfo->materialProps, elementProps, matType); - if (!error.isEmpty()) { - handleError(); - return; - } - - TElement &newMatElem = m_Application->GetElementAllocator().CreateElement( - matName, matType, matClass, - toConstDataRef(elementProps.data(), QT3DSU32(elementProps.size())), - presentation, container, false); - newMatElem.SetActive(true); - - // Create image elements - CRegisteredString imageType = strTable.RegisterStr("Image"); - QMapIterator<QString, QMap<QString, QString>> texIter(materialInfo->textureProps); - QHash<QString, TElement *> imageElementMap; - while (texIter.hasNext()) { - texIter.next(); - elementProps.clear(); - createElementPropsFromDefProps(texIter.value(), elementProps, imageType); - if (!error.isEmpty()) { - m_Application->GetElementAllocator().ReleaseElement(newMatElem, true); - handleError(); - return; - } - CRegisteredString imageName = strTable.RegisterStr(texIter.key()); - - TElement &newImageElem = m_Application->GetElementAllocator().CreateElement( - imageName, imageType, CRegisteredString(), - toConstDataRef(elementProps.data(), QT3DSU32(elementProps.size())), - presentation, &newMatElem, false); - imageElementMap.insert(texIter.key(), &newImageElem); - newImageElem.SetActive(true); - } - - // Create render object for the material - qt3ds::render::SGraphObject *newMaterial = nullptr; - CRegisteredString newMatId = strTable.RegisterStr( - (QByteArrayLiteral("__newMat_") + QByteArray::number(++_idCounter)) - .constData()); - if (isCustomMaterial) { - newMaterial = customMaterialSystem->CreateCustomMaterial(matClass, allocator); - newMaterial->m_Id = newMatId; - auto dynObj = static_cast<qt3ds::render::SDynamicObject *>(newMaterial); - - QHashIterator<QString, qt3ds::render::dynamic::SPropertyDefinition> - dynPropIter(dynPropDefs); - while (dynPropIter.hasNext()) { - dynPropIter.next(); - QByteArray propValStr = materialInfo->materialProps.value( - dynPropIter.key()).toUtf8(); - const auto propDesc = dynPropIter.value(); - switch (propDesc.m_DataType) { - case qt3ds::render::NVRenderShaderDataTypes::QT3DSRenderBool: { - bool boolValue = propValStr.compare(QByteArrayLiteral("true"), - Qt::CaseInsensitive) == 0; - setDynamicObjectProperty(*dynObj, propDesc, boolValue); - break; - } - case qt3ds::render::NVRenderShaderDataTypes::QT3DSF32: - setDynamicObjectProperty(*dynObj, propDesc, propValStr.toFloat()); - break; - case qt3ds::render::NVRenderShaderDataTypes::QT3DSI32: - if (!propDesc.m_IsEnumProperty) { - setDynamicObjectProperty(*dynObj, propDesc, propValStr.toInt()); - } else { - const NVConstDataRef<CRegisteredString> &enumNames - = propDesc.m_EnumValueNames; - for (QT3DSU32 i = 0, end = enumNames.size(); i < end; ++i) { - if (propValStr.compare(enumNames[i].c_str()) == 0) { - setDynamicObjectProperty(*dynObj, propDesc, i); - break; - } - } - } - break; - case qt3ds::render::NVRenderShaderDataTypes::QT3DSVec2: - setDynamicObjectProperty(*dynObj, propDesc, parseFloat2Property(propValStr)); - break; - case qt3ds::render::NVRenderShaderDataTypes::QT3DSVec3: - setDynamicObjectProperty(*dynObj, propDesc, parseFloat3Property(propValStr)); - break; - case qt3ds::render::NVRenderShaderDataTypes::QT3DSVec4: - setDynamicObjectProperty(*dynObj, propDesc, parseFloat4Property(propValStr)); - break; - case qt3ds::render::NVRenderShaderDataTypes::NVRenderTexture2DPtr: - case qt3ds::render::NVRenderShaderDataTypes::NVRenderImage2DPtr: { - CRegisteredString regStr; - regStr = strTable.RegisterStr(propValStr); - setDynamicObjectProperty(*dynObj, propDesc, regStr); - break; - } - default: - error = QObject::tr("Unsupported custom material property type for '%1'") - .arg(dynPropIter.key()); - m_Application->GetElementAllocator().ReleaseElement(newMatElem, true); - handleError(); - return; - } - } - } else { - newMaterial = QT3DS_NEW(allocator, qt3ds::render::SDefaultMaterial)(); - newMaterial->m_Id = newMatId; - - // Update element refs for image elements and create graph objects & translators - QHashIterator<QString, TElement *> imageIter(imageElementMap); - while (imageIter.hasNext()) { - imageIter.next(); - TElement *imageElem = imageIter.value(); - UVariant *propValue = newMatElem.FindPropertyValue(imageElem->m_Name); - if (propValue) { - propValue->m_ElementHandle = imageIter.value()->GetHandle(); - - qt3ds::render::SImage *newImageObj - = QT3DS_NEW(allocator, qt3ds::render::SImage)(); - newImageObj->m_Id = strTable.RegisterStr( - (QByteArrayLiteral("__newImage_") - + QByteArray::number(++_idCounter)).constData()); - qt3ds::render::Qt3DSTranslator::CreateTranslatorForElement( - *imageElem, *newImageObj, allocator); - } - } - createdElements << &newMatElem; - } - - qt3ds::render::Qt3DSTranslator::CreateTranslatorForElement(newMatElem, *newMaterial, - allocator); - } - - handleError(); -} - -void CQmlEngineImpl::deleteMaterials(const QStringList &materialNames, IQt3DSRenderer *renderer) -{ - // Material class (i.e. the shader) is not deleted as those can be shared between materials, - // so we just delete the material elements from the container and the related render objects - - // Sort materials to presentations - QMultiHash<QString, QString> presMaterialMap; - QSet<QString> presIds; - for (const auto &matName : materialNames) { - QString presId; - QString localName = matName; - int index = matName.indexOf(QLatin1Char(':')); - if (index != -1) { - presId = matName.left(index); - localName = matName.mid(index + 1); - } - presMaterialMap.insert(presId, localName); - presIds.insert(presId); - } - for (const auto &presId : qAsConst(presIds)) { - QByteArray theId = presId.toUtf8(); - CPresentation *presentation = nullptr; - if (presId.isEmpty()) - presentation = m_Application->GetPrimaryPresentation(); - else - presentation = m_Application->GetPresentationById(theId.constData()); - - if (presentation) { - // Find material container - auto &strTable = presentation->GetStringTable(); - TElement *rootElement = presentation->GetRoot(); - const auto containerName = strTable.RegisterStr("__Container"); - TElement *container = rootElement->FindChild(CHash::HashString(containerName.c_str())); - Q_ASSERT_X(container, __FUNCTION__, - QStringLiteral("No material container found for presentation: '%1'") - .arg(presId).toUtf8()); - - QVector<TElement *> elementsToDelete; - const QList<QString> matNames = presMaterialMap.values(presId); - for (const auto &materialName : matNames) { - TElement *firstChild = nullptr; - TElement *nextChild = container->GetChild(); - firstChild = nextChild; - bool added = false; - while (nextChild) { - QString childName = QString::fromUtf8(nextChild->m_Name); - if (childName == materialName) { - elementsToDelete << nextChild; - added = true; - break; - } - nextChild = nextChild->GetSibling(); - } - if (!added) { - if (presId.isEmpty()) { - qWarning() << __FUNCTION__ - << QStringLiteral("Could not find material '%1'") - .arg(materialName); - } else { - qWarning() << __FUNCTION__ - << QStringLiteral("Could not find material '%1' in '%2'") - .arg(materialName).arg(presId); - } - } - } - deleteElements(elementsToDelete, renderer); - } else { - qWarning() << __FUNCTION__ << "Warning: Presentation ID could not be resolved:" - << presId; - } - } -} - -void CQmlEngineImpl::createMesh(const QString &name, qt3dsimp::Mesh *mesh, - qt3ds::render::IBufferManager *bufferManager) -{ - // Add the custom meshes to buffer manager. - bufferManager->loadCustomMesh(name, mesh); -} - -void CQmlEngineImpl::deleteMeshes(const QStringList &meshNames, - qt3ds::render::IBufferManager *bufferManager) -{ - for (const auto &meshName : meshNames) { - if (!meshName.isEmpty()) { - CRegisteredString regName = bufferManager->GetStringTable().RegisterStr(meshName); - bufferManager->InvalidateBuffer(regName); - } - } -} - -void CQmlEngineImpl::GotoSlide(const char *component, const char *slideName, - const SScriptEngineGotoSlideArgs &inArgs) -{ - TElement *theTarget = getTarget(component); - if (theTarget) { - CQmlCommandHelper::SetupGotoSlideCommand(*theTarget, slideName, inArgs); - } else { - qCWarning(qt3ds::INVALID_OPERATION) - << "CQmlEngineImpl::GotoSlide: Unable to find component " << component; - } -} - -void CQmlEngineImpl::GotoSlideRelative(const char *component, bool inNextSlide, bool inWrap, - const SScriptEngineGotoSlideArgs &inArgs) -{ - TElement *theTarget = getTarget(component); - if (theTarget) { - theTarget = &theTarget->GetComponentParent(); - if (theTarget && theTarget->GetActive()) { - TComponent *theComponent = static_cast<TComponent *>(theTarget); - Q3DStudio::INT32 theSlide = theComponent->GetCurrentSlide(); - Q3DStudio::INT32 theSlideCount = theComponent->GetSlideCount(); - theSlide = inNextSlide ? theSlide + 1 : theSlide - 1; - if (theSlide < 1) { - if (inWrap) - theSlide = theSlideCount - 1; - else - theSlide = 1; - } else if (theSlide == theSlideCount) { - if (inWrap) - theSlide = 1; - else - theSlide = theSlideCount - 1; - } - if (theSlide != theComponent->GetCurrentSlide()) { - CQmlCommandHelper::SetupGotoSlideCommand(*theTarget, theSlide, inArgs); - } - } else { - qCCritical(qt3ds::INVALID_OPERATION) - << "QmlEngine::GotoSlideRelative: Component is not active: " << component; - } - } else { - qCCritical(qt3ds::INVALID_OPERATION) - << "QmlEngine::GotoSlideRelative: failed to find component: " << component; - } -} - -void CQmlEngineImpl::SetPresentationAttribute(const char *presId, const char *, const char *value) -{ - if (isTrivial(presId)) - return; - if (presId[0] == '#') - ++presId; - CPresentation *thePresentation = m_Application->GetPresentationById(presId); - if (thePresentation) { - bool active = AreEqualCaseless(nonNull(value), "True"); - thePresentation->SetActive(active); - } -} - -void CQmlEngineImpl::GotoSlideIndex(const char *component, const Q3DStudio::INT32 slideIndex, - const SScriptEngineGotoSlideArgs &inArgs) -{ - TElement *theTarget = getTarget(component); - if (theTarget) { - CQmlCommandHelper::SetupGotoSlideCommand(*theTarget, slideIndex, inArgs); - } else { - qCWarning(qt3ds::INVALID_OPERATION) - << "CQmlEngineImpl::GotoSlide: Unable to find component " << component; - } -} - -bool CQmlEngineImpl::GetSlideInfo(const char *element, int ¤tIndex, int &previousIndex, - QString ¤tName, QString &previousName) -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - - TElement *theTarget = getTarget(element); - if (theTarget && theTarget->IsComponent()) { - IPresentation *thePresentation = theTarget->GetBelongedPresentation(); - TComponent *theComponent = thePresentation->GetComponentManager().GetComponent(theTarget); - currentIndex = int(theComponent->GetCurrentSlide()); - previousIndex = int(theComponent->GetPreviousSlide()); - if (currentIndex > 0) { - currentName = QString::fromLocal8Bit( - thePresentation->GetSlideSystem().GetSlideName( - qt3ds::runtime::SSlideKey(*theComponent, QT3DSU32(currentIndex)))); - } else { - currentName.clear(); - } - if (previousIndex > 0) { - previousName = QString::fromLocal8Bit( - thePresentation->GetSlideSystem().GetSlideName( - qt3ds::runtime::SSlideKey(*theComponent, QT3DSU32(previousIndex)))); - } else { - previousName.clear(); - } - return true; - } else { - qCCritical(qt3ds::INVALID_OPERATION) - << "CQmlEngineImpl::GetSlideInfo: Supplied element is not a component " << element; - } - return false; -} - -void CQmlEngineImpl::GotoTime(const char *component, const Q3DStudio::FLOAT time) -{ - TElement *theTarget = getTarget(component); - if (theTarget && theTarget->GetActive()) { - UVariant theArg1; - UVariant theArg2; - - IPresentation *thePresentation = theTarget->GetBelongedPresentation(); - - theArg1.m_INT32 = static_cast<INT32>(time * 1000); - - TElement *theParentTarget = &theTarget->GetComponentParent(); - - thePresentation->FireCommand(COMMAND_GOTOTIME, theParentTarget, &theArg1, &theArg2); - } -} - -bool CQmlEngineImpl::RegisterCallback(Q3DStudio::UINT32 callbackType, - const TScriptCallback inCallback, void *inUserData) -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - return m_ScriptCallbacks.RegisterCallback(callbackType, inCallback, inUserData); -} - -void CQmlEngineImpl::ProcessFrameCallbacks(IPresentation *) -{ - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - m_ScriptCallbacks.ProcessCallbacks(); - - for (Q3DSQmlScript *script : m_scripts) - script->update(); -} - -void CQmlEngineImpl::ProcessSignal(IPresentation *inPresentation, - const SEventCommand &inCommand) -{ - using qt3ds::runtime::TIdValuePair; - QML_ENGINE_MULTITHREAD_PROTECT_METHOD; - TElement *theElement = inCommand.m_Target; // the element that is a behavior - - CPresentation *thePresentation = (CPresentation *)inPresentation; - // IParametersSystem& theParametersManager = thePresentation->GetParametersSystem(); - qt3ds::foundation::IStringTable &theStrTable(thePresentation->GetStringTable()); - - CRegisteredString theSignal = theStrTable.HandleToStr(inCommand.m_Arg1.m_INT32); - - if (!theSignal.IsValid() || m_EmitSignalDataList.size() > CQmlEngineImpl::MAX_ACTION_QUEUE_SIZE) - return; - - TEmitSignalPtr theTemp = QT3DS_NEW(m_Foundation.getAllocator(), SEmitSignalData)( - m_Foundation.getAllocator(), inCommand.m_Arg1.m_INT32, theElement); - m_EmitSignalDataList.push_back(theTemp); -} - - -//============================================================================== -/** -* Handle custom actions -* @param inCommand carrier of command and parameter information -*/ -void CQmlEngineImpl::ProcessCustomActions(IPresentation *presentation, - const SEventCommand &command) -{ - TElement *element = command.m_Target; - for (Q3DSQmlScript *script : m_scripts) { - if (script->hasBehavior(element)) { - IParametersSystem ¶metersManager - = static_cast<CPresentation *>(presentation)->GetParametersSystem(); - INT32 groupId = command.m_Arg1.m_INT32; - UINT32 numParams = parametersManager.GetNumParameters(groupId); - if (numParams == 0) { - QT3DS_ASSERT(false); - return; - } - - qt3ds::runtime::TIdValuePair tempData = parametersManager.GetParameter(groupId, 0); - if (tempData.first != CHash::HashString("string")) { - QT3DS_ASSERT(false); - return; - } - - CRegisteredString functionName = presentation->GetStringTable().HandleToStr( - tempData.second.m_StringHandle); - script->call(functionName.c_str()); - return; - } - } -} - -bool CQmlEngineImpl::PeekSignal(TElement *&outElement, char *&outName) -{ - if (m_EmitSignalDataList.empty()) - return false; - - NVScopedRefCounted<SEmitSignalData> theAction = m_EmitSignalDataList.front(); - m_EmitSignalDataList.pop_front(); - - outElement = theAction->m_TargetElement; - if (outElement) { - IPresentation *thePresentation = outElement->GetBelongedPresentation(); - qt3ds::foundation::IStringTable &theStrTable(thePresentation->GetStringTable()); - CRegisteredString theSignal = theStrTable.HandleToStr(theAction->m_SignalNameHandler); - outName = (char *)theSignal.c_str(); - } else { - qCWarning(qt3ds::INVALID_OPERATION) - << "CQmlEngineImpl::PeekCustomAction: Unable to find element: EmitSignal queue error"; - outName = NULL; - } - - return true; -} - -void CQmlEngineImpl::createComponent(QQmlComponent *component, TElement *element) -{ - TElement *parent = element->GetParent(); - if (!parent) - return; - - QQmlContext *context = new QQmlContext(&m_engine, &m_engine); - QObject *obj = component->beginCreate(context); - if (!obj) { - context->deleteLater(); - return; - } - Q3DSQmlBehavior *behaviorObject = qobject_cast<Q3DSQmlBehavior *>(obj); - if (behaviorObject == nullptr) { - obj->deleteLater(); - context->deleteLater(); - return; - } - - auto script = new Q3DSQmlScript(*this, *behaviorObject, *element, *parent); - component->completeCreate(); - behaviorObject->setScript(script); - - script->setParent(component); - obj->setParent(script); - m_scripts.push_back(script); -} - -TElement *CQmlEngineImpl::getTarget(const char *component) { - TElement *target = NULL; - QStringList split = QString(component).split(":"); - if (split.size() > 1) { - target = CQmlElementHelper::GetElement( - *m_Application, - m_Application->GetPresentationById(split.at(0).toStdString().c_str()), - split.at(1).toStdString().c_str(), NULL); - } else { - target = CQmlElementHelper::GetElement( - *m_Application, - m_Application->GetPrimaryPresentation(), - split.at(0).toStdString().c_str(), NULL); - } - return target; -} - -void CQmlEngineImpl::listAllElements(TElement *root, QList<TElement *> &elements) -{ - elements.append(root); - TElement *nextChild = root->GetChild(); - while (nextChild) { - listAllElements(nextChild, elements); - nextChild = nextChild->GetSibling(); - } -} - -// Initializes datainput bindings in the presentation starting by default from the root element. -// If inElements is specified, only parses the specified elements. -void CQmlEngineImpl::initializeDataInputsInPresentation(CPresentation &presentation, - bool isPrimary, - QList<TElement *> inElements) -{ - QList<TElement *> elements; - if (!inElements.empty()) { - elements = inElements; - } else { - TElement *parent = presentation.GetRoot(); - listAllElements(parent, elements); - } - qt3ds::runtime::DataInputMap &diMap = m_Application->dataInputMap(); - -// #TODO: Remove below once QT3DS-3510 has been implemented in the editor - qt3ds::runtime::DataOutputMap &doMap = m_Application->dataOutputMap(); -// #TODO: Remove above once QT3DS-3510 has been implemented in the editor - - qt3ds::foundation::IStringTable &strTable(presentation.GetStringTable()); - QHash<CRegisteredString, qt3ds::runtime::DataOutputDef> elementPathToDataOutputDefMap; - for (TElement *element : qAsConst(elements)) { - Option<QT3DSU32> ctrlIndex = element->FindPropertyIndex(ATTRIBUTE_CONTROLLEDPROPERTY); - if (ctrlIndex.hasValue()) { - Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> propertyInfo = - element->GetPropertyByIndex(*ctrlIndex); - UVariant *valuePtr = propertyInfo->second; - QString valueStr = - QString::fromUtf8(strTable.HandleToStr(valuePtr->m_StringHandle)); - if (!valueStr.isEmpty()) { - QStringList splitValues = valueStr.split(QChar(' ')); - for (int i = 1; i < splitValues.size(); i += 2) { - QString controllerName = splitValues[i - 1]; - // remove datainput name prefix "$" - controllerName.remove(0, 1); - if (diMap.contains(controllerName)) { - qt3ds::runtime::DataInOutAttribute ctrlElem; - if (!isPrimary) { - // Prepend presentation id to element path - ctrlElem.elementPath = presentation.GetName(); - ctrlElem.elementPath.append(QByteArrayLiteral(":")); - } - ctrlElem.attributeName.append(splitValues[i].toUtf8()); - if (ctrlElem.attributeName.first() == QByteArrayLiteral("@timeline")) { - ctrlElem.propertyType = ATTRIBUTETYPE_DATAINPUT_TIMELINE; - TElement *component = &element->GetComponentParent(); - ctrlElem.elementPath.append(component->m_Path); - } else if (ctrlElem.attributeName.first() == QByteArrayLiteral("@slide")) { - ctrlElem.propertyType = ATTRIBUTETYPE_DATAINPUT_SLIDE; - TElement *component = &element->GetComponentParent(); - ctrlElem.elementPath.append(component->m_Path); - } else if (diMap[controllerName].type - == qt3ds::runtime::DataInOutTypeVector3) { - // special handling for vector datatype to handle - // expansion from <propertyname> to <propertyname>.x .y .z - QVector<QByteArray> attVec; - bool success = getAttributeVector3( - attVec, ctrlElem.attributeName.first().constData(), - element); - if (!attVec.empty() && success) { - ctrlElem.attributeName = attVec; - ctrlElem.elementPath.append(element->m_Path); - ctrlElem.propertyType = ATTRIBUTETYPE_FLOAT3; - } else { - qWarning() << __FUNCTION__ << "Property " - << ctrlElem.attributeName.first() - << " was not expanded to vector"; - ctrlElem.propertyType = ATTRIBUTETYPE_NONE; - } - } else if (diMap[controllerName].type - == qt3ds::runtime::DataInOutTypeVector2) { - // special handling for vector datatype to handle - // expansion from <propertyname> to <propertyname>.x .y - QVector<QByteArray> attVec; - bool success = getAttributeVector2( - attVec, ctrlElem.attributeName.first().constData(), - element); - if (!attVec.empty() && success) { - ctrlElem.attributeName = attVec; - ctrlElem.elementPath.append(element->m_Path); - ctrlElem.propertyType = ATTRIBUTETYPE_FLOAT2; - } else { - qWarning() << __FUNCTION__ << "Property " - << ctrlElem.attributeName.first() - << " was not expanded to vector"; - ctrlElem.propertyType = ATTRIBUTETYPE_NONE; - } - } else if (diMap[controllerName].type - == qt3ds::runtime::DataInOutTypeEvaluator) { - diMap[controllerName].evalFunc - = buildJSFunc(diMap[controllerName].evaluator); - auto referencedDIs = resolveDependentDatainputs( - diMap[controllerName].evaluator, controllerName); - // add this evaluator datainput to the dependent list - // for those datainputs that are used in the expression - // for this evaluator - for (auto ref : referencedDIs) - diMap[ref].dependents.append(controllerName); - - ctrlElem.elementPath.append(element->m_Path); - TStringHash attHash = CHash::HashAttribute( - ctrlElem.attributeName.first().constData()); - Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> attInfo - = element->FindProperty(attHash); - if (attInfo.hasValue()) - ctrlElem.propertyType = attInfo->first.m_Type; - } else { - // all other scalar datatypes - ctrlElem.elementPath.append(element->m_Path); - TStringHash attHash = CHash::HashAttribute( - ctrlElem.attributeName.first().constData()); - Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> attInfo - = element->FindProperty(attHash); - if (attInfo.hasValue()) { - ctrlElem.propertyType = attInfo->first.m_Type; - } else { - ctrlElem.propertyType = ATTRIBUTETYPE_NONE; - qWarning() << __FUNCTION__ << "Property " - << ctrlElem.attributeName.first() << " not existing!"; - } - } - qt3ds::runtime::DataInputDef &diDef = diMap[controllerName]; - diDef.controlledAttributes.append(ctrlElem); - -// #TODO: Remove below once QT3DS-3510 has been implemented in the editor - // Note, in this temp implementation only the LAST of multiple attributes - // will be notified from the object under the DataInput name.. - qt3ds::runtime::DataInputDef inDef = diMap[controllerName]; - qt3ds::runtime::DataOutputDef &doDef = doMap[controllerName]; - doDef.observedAttribute = ctrlElem; - doDef.type = inDef.type; - doDef.min = inDef.min; - doDef.max = inDef.max; - - if (ctrlElem.propertyType == ATTRIBUTETYPE_DATAINPUT_TIMELINE) { - // Find the TElement for the @timeline attrib - TElement *target = nullptr; - QStringList split - = QString(ctrlElem.elementPath).split(QLatin1Char(':')); - if (split.size() > 1) { - target = CQmlElementHelper::GetElement( - *m_Application, - m_Application->GetPresentationById( - split.at(0).toStdString().c_str()), - split.at(1).toStdString().c_str(), nullptr); - } else { - target = CQmlElementHelper::GetElement( - *m_Application, - m_Application->GetPrimaryPresentation(), - split.at(0).toStdString().c_str(), nullptr); - } - - doDef.timelineComponent = static_cast<TComponent *>(target); - } else if (ctrlElem.propertyType == ATTRIBUTETYPE_DATAINPUT_SLIDE) { - // Slide notifications are already done with separate signal - // No need to process - } else { - // Other than slide or timeline attributes are handled by CPresentation - CRegisteredString rString = strTable.RegisterStr(ctrlElem.elementPath); - elementPathToDataOutputDefMap.insertMulti(rString, doDef); - } -// #TODO: Remove above once QT3DS-3510 has been implemented in the editor - } - } - } - } - } - -// #TODO: Remove below once QT3DS-3510 has been implemented in the editor - presentation.AddToDataOutputMap(elementPathToDataOutputDefMap); -// #TODO: Remove above once QT3DS-3510 has been implemented in the editor -} - -void CQmlEngineImpl::initializeDataOutputsInPresentation(CPresentation &presentation, - bool isPrimary) -{ - TElement *parent = presentation.GetRoot(); - QList<TElement *> elements; - listAllElements(parent, elements); - qt3ds::runtime::DataOutputMap &doMap = m_Application->dataOutputMap(); - - qt3ds::foundation::IStringTable &strTable(presentation.GetStringTable()); - QHash<CRegisteredString, qt3ds::runtime::DataOutputDef> elementPathToDataOutputDefMap; - for (TElement *element : qAsConst(elements)) { - Option<QT3DSU32> ctrlIndex = element->FindPropertyIndex(ATTRIBUTE_OBSERVEDPROPERTY); - if (ctrlIndex.hasValue()) { - Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> propertyInfo = - element->GetPropertyByIndex(*ctrlIndex); - UVariant *valuePtr = propertyInfo->second; - QString valueStr = - QString::fromUtf8(strTable.HandleToStr(valuePtr->m_StringHandle)); - - if (!valueStr.isEmpty()) { - QStringList splitValues = valueStr.split(QLatin1Char(' ')); - - // Single value pair expected for DataOutputs - QString observerName = splitValues[0]; - QString observedAttribute = splitValues[1]; - // Remove DataOutput name prefix "$" - observerName.remove(0, 1); - qt3ds::runtime::DataOutputDef &doDef = doMap[observerName]; - - if (doMap.contains(observerName)) { - qt3ds::runtime::DataInOutAttribute obsElem; - if (!isPrimary) { - // Prepend presentation id to element path - obsElem.elementPath = presentation.GetName(); - obsElem.elementPath.append(QByteArrayLiteral(":")); - } - - obsElem.attributeName.append(observedAttribute.toUtf8()); - - if (obsElem.attributeName.first() == QByteArrayLiteral("@timeline")) { - // Timeline requires special additional handling - obsElem.propertyType = ATTRIBUTETYPE_DATAINPUT_TIMELINE; - TElement *component = &element->GetComponentParent(); - obsElem.elementPath.append(component->m_Path); - - // Find the TElement for the @timeline attrib - TElement *target = nullptr; - QStringList split = QString(obsElem.elementPath).split(QLatin1Char(':')); - if (split.size() > 1) { - target = CQmlElementHelper::GetElement( - *m_Application, - m_Application->GetPresentationById( - split.at(0).toStdString().c_str()), - split.at(1).toStdString().c_str(), nullptr); - } else { - target = CQmlElementHelper::GetElement( - *m_Application, - m_Application->GetPrimaryPresentation(), - split.at(0).toStdString().c_str(), nullptr); - } - doDef.timelineComponent = static_cast<TComponent *>(target); - } else if (obsElem.attributeName.first() == QByteArrayLiteral("@slide")) { - // Slides are ignored if set as we have separate signal in the API for - // slide transitions - } else { - // Every other type is handled by CPresentation - obsElem.elementPath.append(element->m_Path); - TStringHash attHash = CHash::HashAttribute( - obsElem.attributeName.first().constData()); - Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> attInfo - = element->FindProperty(attHash); - if (attInfo.hasValue()) { - obsElem.propertyType = attInfo->first.m_Type; - } else { - obsElem.propertyType = ATTRIBUTETYPE_NONE; - qWarning() << __FUNCTION__ << "Property" - << obsElem.attributeName.first() << "not existing!"; - } - - doDef.observedAttribute = obsElem; - CRegisteredString rString = strTable.RegisterStr(obsElem.elementPath); - elementPathToDataOutputDefMap.insertMulti(rString, doDef); - } - } - } - } - } - - // Inform the presentation of the ready data output defs - presentation.AddToDataOutputMap(elementPathToDataOutputDefMap); -} - -// Bit clumsy way of getting from "position" to "position .x .y .z" and enabling datainput -// support for vectorized types. UIP parser has already thrown away all vector -// type attributes and at this point we are operating with scalar components only. -// We check if this element has a property attName.x or attName.r to find out it -// we should expand property attName to XYZ or RGB vector -bool CQmlEngineImpl::getAttributeVector3(QVector<QByteArray> &outAttVec, - const QByteArray &attName, - TElement *elem) -{ - auto hashName = Q3DStudio::CHash::HashAttribute(attName + ".x"); - - if (!elem->FindProperty(hashName).isEmpty()) { - outAttVec.append(attName + ".x"); - outAttVec.append(attName + ".y"); - outAttVec.append(attName + ".z"); - return true; - } - hashName = Q3DStudio::CHash::HashAttribute(attName + ".r"); - if (!elem->FindProperty(hashName).isEmpty()) { - outAttVec.append(attName + ".r"); - outAttVec.append(attName + ".g"); - outAttVec.append(attName + ".b"); - return true; - } - return false; -} - -bool CQmlEngineImpl::getAttributeVector2(QVector<QByteArray> &outAttVec, - const QByteArray &attName, - TElement *elem) -{ - auto hashName = Q3DStudio::CHash::HashAttribute(attName + ".x"); - - if (!elem->FindProperty(hashName).isEmpty()) { - outAttVec.append(attName + ".x"); - outAttVec.append(attName + ".y"); - return true; - } - - hashName = Q3DStudio::CHash::HashAttribute(attName + ".u"); - if (!elem->FindProperty(hashName).isEmpty()) { - outAttVec.append(attName + ".u"); - outAttVec.append(attName + ".v"); - return true; - } - return false; -} - -QJSValue CQmlEngineImpl::buildJSFunc(const QString &userFunc) -{ - auto res = this->m_engine.evaluate(userFunc); - if (res.isError()) { - qWarning() << __FUNCTION__ - << "Uncaught exception during datainput evaluation. Evaluator function" << userFunc; - } - return res; -} - -QVariant CQmlEngineImpl::callJSFunc(const QString &controllerName, - qt3ds::runtime::DataInputDef &diDef, - const QVariant::Type type) -{ - qt3ds::runtime::DataInputMap &diMap = m_Application->dataInputMap(); - QJSValueList args; - QVector<QString> sourceDIs = resolveDependentDatainputs(diDef.evaluator, controllerName); - - // get the most recent set values for datainput sources (arguments) in the expression - for (auto diVal : sourceDIs) - args << this->m_engine.toScriptValue(diMap[diVal].value); - - if (diDef.evalFunc.isCallable()) { - QJSValue res = diDef.evalFunc.call(args); - if (res.isError()) { - qWarning() << __FUNCTION__ << "Error during datainput" << controllerName - << "evaluator call:" << res.toString() << "\nEvaluator function" - << diDef.evaluator; - return QVariant::Invalid; - } - - QVariant ret = res.toVariant(); - if (ret.isValid() && isMatchingDatatype(ret.type(), type)) { - // further check if the result is valid number - if (ret.type() == QVariant::Double && qIsNaN(res.toNumber())) { - qWarning() << __FUNCTION__ << "Datainput" << controllerName << "evaluator" - << "result not a number (NaN)." - << "\nEvaluator function" << diDef.evaluator; - return QVariant::Invalid; - } else { - return ret; - } - } else { - qWarning() << __FUNCTION__ << "Datainput" << controllerName << "evaluator" - << "result not valid or matching with target attribute type. Result type" - << QVariant::typeToName(ret.type()) << " target attribute type " - << QVariant::typeToName(type) << "\nEvaluator function" << diDef.evaluator; - } - } else { - qWarning() << __FUNCTION__ << "Datainput" << controllerName << "evaluator" - << diDef.evaluator << " not valid callable"; - } - return QVariant::Invalid; -} - -bool CQmlEngineImpl::isMatchingDatatype(QVariant::Type resultType, QVariant::Type propertyType) -{ - if (resultType == propertyType) - return true; - // Allow binding from numeric datainput to string target - if ((resultType == QVariant::Double || resultType == QVariant::Int - || resultType == QVariant::LongLong) - && (propertyType == QVariant::Double || propertyType == QVariant::Int - || propertyType == QVariant::LongLong || propertyType == QVariant::String)) { - return true; - } - return false; -} - -QVector<QString> CQmlEngineImpl::resolveDependentDatainputs(const QString &expression, - const QString &controllerName) -{ - QVector<QString> ret; - qt3ds::runtime::DataInputMap &diMap = m_Application->dataInputMap(); - if (!expression.contains("function", Qt::CaseInsensitive)) { - qWarning() << __FUNCTION__ << "Function keyword not found in datainput" - << controllerName << "evaluator"; - return QVector<QString>(); - } - - int argListStart = expression.indexOf("function(") + 9; - int argListStop = expression.indexOf(')', argListStart); - QString argstr = expression.mid(argListStart , argListStop - argListStart); - QStringList args = argstr.split(','); - - for (auto di : args) { - auto diTrim = di.trimmed(); - if (diMap.contains(diTrim)) { - if (diMap[diTrim].type == qt3ds::runtime::DataInOutTypeEvaluator - && diTrim != controllerName) { - qWarning() << __FUNCTION__ << "Invalid evaluator function in" << controllerName - << ". Another evaluator is used as source data."; - } else { - ret.append(diTrim); - } - } else { - qWarning() << __FUNCTION__ << "Evaluator in" << controllerName << "evaluator" - << "is using unknown datainput" << diTrim << " as input argument name"; - } - } - return ret; -} - -void CQmlEngineImpl::addStringAttribute(IStringTable &strTable, - CQmlEngineImpl::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)); -} - -void CQmlEngineImpl::addIntAttribute(IStringTable &strTable, - CQmlEngineImpl::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)); -} - -void CQmlEngineImpl::addBoolAttribute(IStringTable &strTable, - CQmlEngineImpl::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)); -} - -void CQmlEngineImpl::addFloatAttribute(IStringTable &strTable, - CQmlEngineImpl::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)); -} - -void CQmlEngineImpl::addFloat2Attribute(IStringTable &strTable, - CQmlEngineImpl::TPropertyDescAndValueList &list, - const QStringList &inAttNames, const QVector2D &inValue) -{ - for (int i = 0; i < 2; ++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)); - } -} - -void CQmlEngineImpl::addFloat3Attribute(IStringTable &strTable, - CQmlEngineImpl::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)); - } -} - -void CQmlEngineImpl::addFloat4Attribute(IStringTable &strTable, - CQmlEngineImpl::TPropertyDescAndValueList &list, - const QStringList &inAttNames, const QVector4D &inValue) -{ - for (int i = 0; i < 4; ++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)); - } -} - -void CQmlEngineImpl::addElementRefAttribute(IStringTable &strTable, - CQmlEngineImpl::TPropertyDescAndValueList &list, - const QString &inAttName, TElement *element) -{ - UVariant theValue; - if (element) { - theValue.m_ElementHandle = element->GetHandle(); - QT3DS_ASSERT(theValue.m_ElementHandle); - } else { - theValue.m_ElementHandle = 0; - } - const CRegisteredString attStr = strTable.RegisterStr(inAttName); - list.push_back(eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_ELEMENTREF), theValue)); -} - -QVector2D CQmlEngineImpl::parseFloat2Property(const QString &propValue) -{ - QVector<QStringRef> values = propValue.splitRef(QLatin1Char(' ')); - QVector2D retVal; - for (int i = 0; i < values.size() && i < 2; ++i) - retVal[i] = values[i].toFloat(); - return retVal; -} - -QVector3D CQmlEngineImpl::parseFloat3Property(const QString &propValue) -{ - QVector<QStringRef> values = propValue.splitRef(QLatin1Char(' ')); - QVector3D retVal; - for (int i = 0; i < values.size() && i < 3; ++i) - retVal[i] = values[i].toFloat(); - return retVal; -} - -QVector4D CQmlEngineImpl::parseFloat4Property(const QString &propValue) -{ - QVector<QStringRef> values = propValue.splitRef(QLatin1Char(' ')); - QVector4D retVal; - for (int i = 0; i < values.size() && i < 4; ++i) - retVal[i] = values[i].toFloat(); - return retVal; -} - -void CQmlEngineImpl::notifyElementCreation(const QStringList &elementNames, const QString &error) -{ - // Notify presentation asynchronously to give renderer time to initialize the elements properly - if (!error.isEmpty()) { - qWarning() << "Warning: Element creation failed:" << error; - QT3DS_ASSERT(false); - } - QTimer::singleShot(0, [this, elementNames, error]() { - m_Application->GetPrimaryPresentation()->signalProxy() - ->SigElementsCreated(elementNames, error); - }); -} - -void CQmlEngineImpl::notifyMaterialCreation(const QStringList &materialNames, const QString &error) -{ - // Notify presentation asynchronously to give renderer time to initialize the materials properly - if (!error.isEmpty()) { - qWarning() << "Warning: Material creation failed:" << materialNames << error; - QT3DS_ASSERT(false); - } - QTimer::singleShot(0, [this, materialNames, error]() { - m_Application->GetPrimaryPresentation()->signalProxy() - ->SigMaterialsCreated(materialNames, error); - }); -} - -void CQmlEngineImpl::deleteElements(const QVector<TElement *> &elements, - IQt3DSRenderer *renderer) -{ - TElement *lastParent = nullptr; - IPresentation *presentation = nullptr; - TElement *component = nullptr; - ISlideSystem *slideSystem = nullptr; - QSet<qt3ds::render::SNode *> parentNodes; - for (auto element : elements) { - TElement *parentElement = element->GetParent(); - if (parentElement != lastParent) { - lastParent = parentElement; - presentation = element->GetBelongedPresentation(); - component = &element->GetComponentParent(); - slideSystem = &presentation->GetSlideSystem(); - } - // Remove element recursively from slide system - slideSystem->removeElement(*component, *element); - - Q_ASSERT(parentElement); - - NVAllocatorCallback &allocator = presentation->GetScene()->allocator(); - - // Recursive deleter for translators and graph objects - std::function<void(TElement *)> deleteRenderObjects; - deleteRenderObjects = [&](TElement *elem) { - TElement *child = elem->m_Child; - while (child) { - TElement *sibling = child->m_Sibling; - deleteRenderObjects(child); - child = sibling; - } - - auto translator = static_cast<qt3ds::render::Qt3DSTranslator *>(elem->GetAssociation()); - if (translator) { - qt3ds::render::GraphObjectTypes::Enum type = translator->GetUIPType(); - if (type == qt3ds::render::GraphObjectTypes::Model) { - auto model = static_cast<qt3ds::render::SModel *>(&translator->RenderObject()); - // Delete material - if (model->m_FirstMaterial) { - auto material = static_cast<qt3ds::render::SReferencedMaterial *>( - model->m_FirstMaterial); - QT3DS_FREE(allocator, material); - } - } - QT3DS_FREE(allocator, &translator->RenderObject()); - QT3DS_FREE(allocator, translator); - } - }; - - qt3ds::render::SNode *node = nullptr; - qt3ds::render::SNode *parentNode = nullptr; - auto translator = static_cast<qt3ds::render::Qt3DSTranslator *>(element->GetAssociation()); - - if (translator) { - if (qt3ds::render::GraphObjectTypes::IsNodeType(translator->GetUIPType())) { - node = &static_cast<qt3ds::render::SNode &>(translator->RenderObject()); - auto parentTranslator = static_cast<qt3ds::render::Qt3DSTranslator *>( - parentElement->GetAssociation()); - if (parentTranslator) { - parentNode = &static_cast<qt3ds::render::SNode &>( - parentTranslator->RenderObject()); - parentNode->RemoveChild(*node); - parentNodes.insert(parentNode); - } - } - // Release child element graph objects/translators - deleteRenderObjects(element); - } - - // Remove element recursively - m_Application->GetElementAllocator().ReleaseElement(*element, true); - } - for (auto parentNode : qAsConst(parentNodes)) - renderer->ChildrenUpdated(*parentNode); -} - -template<typename TDataType> -void CQmlEngineImpl::setDynamicObjectProperty(qt3ds::render::SDynamicObject &material, - const dynamic::SPropertyDefinition &propDesc, - const TDataType &propValue) -{ - memCopy(material.GetDataSectionBegin() + propDesc.m_Offset, &propValue, sizeof(TDataType)); -} - -/** -* @brief Create QML engine -* -* @param[in] inFoundation Pointer to foundation -* @param[in] inTimeProvider Pointer to time provider -* -* @return no return -*/ -CQmlEngine *CQmlEngine::Create(qt3ds::NVFoundationBase &inFoundation, ITimeProvider &inTimeProvider) -{ - return QT3DS_NEW(inFoundation.getAllocator(), CQmlEngineImpl)(inFoundation, inTimeProvider); -} - -} |