diff options
author | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-05-03 17:32:41 +0300 |
---|---|---|
committer | Miikka Heikkinen <miikka.heikkinen@qt.io> | 2019-05-14 12:02:22 +0000 |
commit | 0a82b82de3ad7796cf91a355017a24ace2c830b4 (patch) | |
tree | 431464639e01b1e8313b420c33dbdcc7fbd4683b /src/Runtime | |
parent | d34ae2ca1590c063e26bd294c26accd9e8b605a1 (diff) |
Add material creation to runtime C++ API
Materials can only be created into the material container, animatable
materials are not supported.
Elements using new created materials should not be created before
Q3DSPresentation::materialCreated signal is received.
Task-number: QT3DS-3377
Change-Id: I782f09094d5f7151d7e1dab28b76fbbfdfcb6066
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Jari Karppinen <jari.karppinen@qt.io>
Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Diffstat (limited to 'src/Runtime')
-rw-r--r-- | src/Runtime/Qt3DSRuntimeStatic/Qt3DSRuntimeStatic.pro | 2 | ||||
-rw-r--r-- | src/Runtime/Source/engine/Qt3DSRuntimeView.cpp | 16 | ||||
-rw-r--r-- | src/Runtime/Source/engine/Qt3DSRuntimeView.h | 2 | ||||
-rw-r--r-- | src/Runtime/Source/runtime/Qt3DSApplication.cpp | 4 | ||||
-rw-r--r-- | src/Runtime/Source/runtime/Qt3DSIScriptBridge.h | 6 | ||||
-rw-r--r-- | src/Runtime/Source/runtime/Qt3DSPresentation.cpp | 80 | ||||
-rw-r--r-- | src/Runtime/Source/runtime/Qt3DSPresentation.h | 58 | ||||
-rw-r--r-- | src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp | 590 | ||||
-rw-r--r-- | src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.cpp | 138 | ||||
-rw-r--r-- | src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.h | 49 | ||||
-rw-r--r-- | src/Runtime/Source/uipparser/Qt3DSIPresentation.h | 42 | ||||
-rw-r--r-- | src/Runtime/Source/viewer/Qt3DSViewerApp.cpp | 10 | ||||
-rw-r--r-- | src/Runtime/Source/viewer/Qt3DSViewerApp.h | 2 |
13 files changed, 814 insertions, 185 deletions
diff --git a/src/Runtime/Qt3DSRuntimeStatic/Qt3DSRuntimeStatic.pro b/src/Runtime/Qt3DSRuntimeStatic/Qt3DSRuntimeStatic.pro index 9d5d2a01..1a76455a 100644 --- a/src/Runtime/Qt3DSRuntimeStatic/Qt3DSRuntimeStatic.pro +++ b/src/Runtime/Qt3DSRuntimeStatic/Qt3DSRuntimeStatic.pro @@ -57,6 +57,7 @@ SOURCES += \ ../Source/runtime/Qt3DSSlideSystem.cpp \ ../Source/runtime/Qt3DSTimePolicy.cpp \ ../Source/runtime/q3dsvariantconfig.cpp \ + ../Source/runtime/q3dsmaterialdefinitionparser.cpp \ ../Source/runtimerender/graphobjects/Qt3DSRenderCamera.cpp \ ../Source/runtimerender/graphobjects/Qt3DSRenderDefaultMaterial.cpp \ ../Source/runtimerender/graphobjects/Qt3DSRenderDynamicObject.cpp \ @@ -258,6 +259,7 @@ HEADERS += \ ../Source/runtime/Qt3DSIText.h \ ../Source/runtime/Qt3DSKernelTypes.h \ ../Source/runtime/q3dsvariantconfig_p.h \ + ../Source/runtime/q3dsmaterialdefinitionparser.h \ ../Source/runtimerender/graphobjects/Qt3DSRenderCamera.h \ ../Source/runtimerender/graphobjects/Qt3DSRenderCustomMaterial.h \ ../Source/runtimerender/graphobjects/Qt3DSRenderDefaultMaterial.h \ diff --git a/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp b/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp index 5e6506b3..5d6b0a6c 100644 --- a/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp +++ b/src/Runtime/Source/engine/Qt3DSRuntimeView.cpp @@ -218,6 +218,7 @@ public: void createElement(const QString &parentElementPath, const QString &slideName, const QHash<QString, QVariant> &properties) override; void deleteElement(const QString &elementPath) override; + void createMaterial(const QString &elementPath, const QString &materialDefinition) override; void SetAttribute(const char *elementPath, const char *attributeName, const char *value) override; bool GetAttribute(const char *elementPath, const char *attributeName, void *value) override; @@ -309,6 +310,8 @@ bool CRuntimeView::InitializeGraphics(const QSurfaceFormat &format, bool delayed signalProxy(), &QRuntimeViewSignalProxy::SigSlideExited); QObject::connect(m_Presentation->signalProxy(), &QPresentationSignalProxy::SigCustomSignal, signalProxy(), &QRuntimeViewSignalProxy::SigCustomSignal); + QObject::connect(m_Presentation->signalProxy(), &QPresentationSignalProxy::SigMaterialCreated, + signalProxy(), &QRuntimeViewSignalProxy::SigMaterialCreated); m_TimeProvider.Reset(); return true; @@ -636,6 +639,19 @@ void CRuntimeView::deleteElement(const QString &elementPath) } } +void CRuntimeView::createMaterial(const QString &elementPath, const QString &materialDefinition) +{ + if (m_Application) { + Q3DStudio::CQmlEngine &theBridgeEngine + = static_cast<Q3DStudio::CQmlEngine &>(m_RuntimeFactoryCore->GetScriptEngineQml()); + theBridgeEngine.createMaterial( + elementPath, materialDefinition, + &m_RuntimeFactory->GetQt3DSRenderContext().GetCustomMaterialSystem(), + &m_RuntimeFactory->GetQt3DSRenderContext().GetDynamicObjectSystem(), + &m_RuntimeFactory->GetQt3DSRenderContext().GetRenderer()); + } +} + void CRuntimeView::SetAttribute(const char *elementPath, const char *attributeName, const char *value) { diff --git a/src/Runtime/Source/engine/Qt3DSRuntimeView.h b/src/Runtime/Source/engine/Qt3DSRuntimeView.h index 0bd63010..ec136525 100644 --- a/src/Runtime/Source/engine/Qt3DSRuntimeView.h +++ b/src/Runtime/Source/engine/Qt3DSRuntimeView.h @@ -55,6 +55,7 @@ Q_SIGNALS: void SigSlideEntered(const QString &elementPath, unsigned int index, const QString &name); void SigSlideExited(const QString &elementPath, unsigned int index, const QString &name); void SigCustomSignal(const QString &elementPath, const QString &name); + void SigMaterialCreated(const QString &name); }; namespace qt3ds { @@ -192,6 +193,7 @@ public: virtual void createElement(const QString &parentElementPath, const QString &slideName, const QHash<QString, QVariant> &properties) = 0; virtual void deleteElement(const QString &elementPath) = 0; + virtual void createMaterial(const QString &elementPath, const QString &materialDefinition) = 0; virtual void SetAttribute(const char *elementPath, const char *attributeName, const char *value) = 0; virtual bool GetAttribute(const char *elementPath, const char *attributeName, void *value) = 0; diff --git a/src/Runtime/Source/runtime/Qt3DSApplication.cpp b/src/Runtime/Source/runtime/Qt3DSApplication.cpp index 830f4573..07ca8e4c 100644 --- a/src/Runtime/Source/runtime/Qt3DSApplication.cpp +++ b/src/Runtime/Source/runtime/Qt3DSApplication.cpp @@ -1092,7 +1092,9 @@ struct SApp : public IApplication if (theStream) { theStream = NULL; CPresentation *thePresentation - = Q3DStudio_new(CPresentation) CPresentation(inAsset.m_Id.c_str(), this); + = Q3DStudio_new(CPresentation) CPresentation(inAsset.m_Id.c_str(), + GetProjectDirectory().c_str(), + this); inAsset.m_Presentation = thePresentation; thePresentation->SetFilePath(theFile.c_str()); NVScopedReleasable<IUIPParser> theUIPParser(IUIPParser::Create( diff --git a/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h b/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h index 8f8925d8..8edced36 100644 --- a/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h +++ b/src/Runtime/Source/runtime/Qt3DSIScriptBridge.h @@ -53,6 +53,8 @@ namespace qt3ds { namespace render { class IThreadPool; class IQt3DSRenderer; + class ICustomMaterialSystem; + class IDynamicObjectSystem; } } @@ -164,6 +166,10 @@ public: // Elements qt3ds::render::IQt3DSRenderer *renderer) = 0; virtual void deleteElement(const QString &elementPath, qt3ds::render::IQt3DSRenderer *renderer) = 0; + virtual void createMaterial(const QString &elementPath, const QString &materialDefinition, + qt3ds::render::ICustomMaterialSystem *customMaterialSystem, + qt3ds::render::IDynamicObjectSystem *dynamicObjectSystem, + qt3ds::render::IQt3DSRenderer *renderer) = 0; public: // Components virtual void GotoSlide(const char *component, const char *slideName, diff --git a/src/Runtime/Source/runtime/Qt3DSPresentation.cpp b/src/Runtime/Source/runtime/Qt3DSPresentation.cpp index a4302ad5..ea01878c 100644 --- a/src/Runtime/Source/runtime/Qt3DSPresentation.cpp +++ b/src/Runtime/Source/runtime/Qt3DSPresentation.cpp @@ -28,9 +28,6 @@ ** ****************************************************************************/ -//============================================================================== -// Includes -//============================================================================== #include "Qt3DSPresentation.h" #include "Qt3DSCommandEventTypes.h" #include "Qt3DSIScriptBridge.h" @@ -47,34 +44,28 @@ #include "Qt3DSLogicSystem.h" #include "Qt3DSParametersSystem.h" -//============================================================================== -// Namespace -//============================================================================== +#include <QtCore/qfileinfo.h> + namespace Q3DStudio { -//============================================================================== -// Constants -//============================================================================== -/// Maximum number of Event/Command that can be queued in an Update cycle +// Maximum number of Event/Command that can be queued in an Update cycle const INT32 Q3DStudio_EVENTCOMMANDQUEUECAPACITY = 512; -/// Limit to prevent infinite loop during queue processing +// Limit to prevent infinite loop during queue processing const INT32 Q3DStudio_MAXEVENTCOMMANDLOOPCOUNT = Q3DStudio_EVENTCOMMANDQUEUECAPACITY * 10; #ifdef WIN32 #pragma warning(push) #pragma warning(disable : 4355) #endif -//============================================================================== -/** - * Constructor - */ -CPresentation::CPresentation(const CHAR *inName, qt3ds::runtime::IApplication *inApplication) + +CPresentation::CPresentation(const QString &inName, const QString &projectPath, + qt3ds::runtime::IApplication *inApplication) : m_Name(inName) , m_Application(inApplication) - , m_Scene(NULL) - , m_ActivityZone(NULL) - , m_RootElement(NULL) + , m_Scene(nullptr) + , m_ActivityZone(nullptr) + , m_RootElement(nullptr) , m_EventCommandQueue(Q3DStudio_EVENTCOMMANDQUEUECAPACITY, "EventCommandQueue") , m_IsProcessingEventCommandQueue(false) , m_ComponentManager(*this) @@ -85,6 +76,7 @@ CPresentation::CPresentation(const CHAR *inName, qt3ds::runtime::IApplication *i , m_OffsetInvalid(true) , m_Active(true) { + m_projectPath = QFileInfo(projectPath).absoluteFilePath(); m_Size.m_Width = 0; m_Size.m_Height = 0; m_Size.m_ScaleMode = SCALEMODE_UNKNOWN; @@ -103,15 +95,10 @@ CPresentation::CPresentation(const CHAR *inName, qt3ds::runtime::IApplication *i #pragma warning(pop) #endif -//============================================================================== -/** - * Destructor - */ CPresentation::~CPresentation() { } -//============================================================================== /** * Registers an element for notification when events fired on it. * @param inElement target element to monitor @@ -129,7 +116,6 @@ void CPresentation::RegisterEventCallback(TElement *inElement, const TEventComma inElement->SetFlag(ELEMENTFLAG_PICKENABLED, true); } -//============================================================================== /** * Unregisters a previously registered event callback. * @param inElement target element to monitor @@ -183,7 +169,6 @@ void CPresentation::PreUpdate(const TTimeUnit inGlobalTime) ProcessEventCommandQueue(); } -//============================================================================== /** * Update the presentation to the current time. This will start triggering the * various stages of the presentation frame rhythm @@ -230,7 +215,6 @@ void CPresentation::PostUpdate(const TTimeUnit inGlobalTime) m_PreviousGlobalTime = inGlobalTime; } -//============================================================================== /** * Process the Event/Command queue completely * PostEventCommand is the method that will add new Event/Command to the queue. @@ -288,7 +272,6 @@ BOOL CPresentation::ProcessEventCommandQueue() return theResult; } -//============================================================================== /** * Pass incoming event to event consumers immediately * @param ioEvent the incoming event @@ -318,7 +301,6 @@ void CPresentation::ProcessEvent(SEventCommand &ioEvent, INT32 &ioEventCount) } } -//============================================================================== /** * Handle event bubbling * @param ioEvent the incoming event @@ -330,7 +312,7 @@ void CPresentation::ProcessEventBubbling(SEventCommand &ioEvent, INT32 &ioEventC // Check for onGroupedMouseOver/Out // arg1 = the original onMouseOut model and arg2 = the original onMouseOver model if (ioEvent.m_Type == ON_MOUSEOUT) { - // If original onMouseOver model is NULL or not a descendent, fire onGroupedMouseOut + // If original onMouseOver model is nullptr or not a descendent, fire onGroupedMouseOut TElement *theMouseOverModel = static_cast<TElement *>(ioEvent.m_Arg2.m_VoidPointer); if (!theMouseOverModel || !ioEvent.m_Target->IsDescendent(*theMouseOverModel)) { SEventCommand theEvent = ioEvent; @@ -345,7 +327,7 @@ void CPresentation::ProcessEventBubbling(SEventCommand &ioEvent, INT32 &ioEventC ioEvent.m_Arg2.m_VoidPointer = ioEvent.m_Target; } } else if (ioEvent.m_Type == ON_MOUSEOVER) { - // If original onMouseOut model is NULL or not a descendent, fire onGroupedMouseOver + // If original onMouseOut model is nullptr or not a descendent, fire onGroupedMouseOver TElement *theMouseOutModel = static_cast<TElement *>(ioEvent.m_Arg1.m_VoidPointer); if (!theMouseOutModel || !ioEvent.m_Target->IsDescendent(*theMouseOutModel)) { SEventCommand theEvent = ioEvent; @@ -379,7 +361,6 @@ void CPresentation::ProcessEventBubbling(SEventCommand &ioEvent, INT32 &ioEventC } } -//============================================================================== /** * Execute command immediately * @param inCommand incoming command structure @@ -454,7 +435,6 @@ void CPresentation::ProcessCommand(const SEventCommand &inCommand) } } -//============================================================================== /** * Put an Event in the queue to be processed later during the Event/Command * processing stage in Update @@ -472,7 +452,6 @@ void CPresentation::FireEvent(const SEventCommand &inEvent) theEventCommand.m_IsEvent = true; } -//============================================================================== /** * Put an Event in the queue to be processed later during the Event/Command * processing stage in Update See ProcessEventCommandQueue for more @@ -508,7 +487,6 @@ void CPresentation::FireEvent(const TEventCommandHash inEventType, TElement *inT m_EventCommandQueue.NewEntry() = theEvent; } -//============================================================================== /** * Put a Command in the queue to be processed later during the Event/Command * processing stage in Update. See ProcessEventCommandQueue for more information @@ -564,7 +542,7 @@ void CPresentation::ProcessEvent(SEventCommand &inEvent) INT32 theEventProcessedCount = 0; ProcessEvent(inEvent, theEventProcessedCount); } -//============================================================================== + /** * This method is triggered after the presentation is streamed in. At this point, * all the stores will be loaded up. @@ -574,7 +552,6 @@ void CPresentation::OnPresentationLoaded() m_FrameData.Reserve(1000 /*m_ElementManager.GetElementCount( )*/); } -//============================================================================== /** * Set the full path for this presentation. This can be used by anyone who * knows the presentation to form relative paths. @@ -582,20 +559,26 @@ void CPresentation::OnPresentationLoaded() */ void CPresentation::SetFilePath(const CHAR *inPath) { - m_FilePath = inPath; + m_FilePath = QFileInfo(inPath).absoluteFilePath(); } -//============================================================================== /** * Gets the full file path for this presentation. This can be used by anyone who * knows the presentation to form relative correct paths. */ -QString CPresentation::GetFilePath() +QString CPresentation::GetFilePath() const { return m_FilePath; } -//============================================================================== +/** + * Gets the absolute file path for the project that owns this presentation. + */ +QString CPresentation::getProjectPath() const +{ + return m_projectPath; +} + /** * Gets the pause state * @return true if the presentation is paused, false if otherwise @@ -605,7 +588,6 @@ BOOL CPresentation::GetPause() const return m_Paused; } -//============================================================================== /** * Sets the pause state * @param inPause set true to pause, set false if otherwise @@ -615,7 +597,6 @@ void CPresentation::SetPause(const BOOL inPause) m_Paused = inPause ? true : false; } -//============================================================================== /** * Simple manager access: Scene */ @@ -645,7 +626,6 @@ bool CPresentation::GetActive() const return m_Active; } -//============================================================================== /** * Simple manager access: Scene */ @@ -654,7 +634,6 @@ IScene *CPresentation::GetScene() const return m_Scene; } -//============================================================================== /** * Simple manager access: Script Bridge Qml */ @@ -663,10 +642,9 @@ IScriptBridge *CPresentation::GetScriptBridgeQml() if (m_Application) return &m_Application->GetRuntimeFactoryCore().GetScriptEngineQml(); - return NULL; + return nullptr; } -//============================================================================== /** * Simple manager access: Component Manager */ @@ -675,7 +653,6 @@ IComponentManager &CPresentation::GetComponentManager() return m_ComponentManager; } -//============================================================================== /** * Simple manager access: Slide Manager */ @@ -684,7 +661,6 @@ ISlideSystem &CPresentation::GetSlideSystem() return *m_SlideSystem; } -//============================================================================== /** * Simple manager access: Animation Manager */ @@ -693,7 +669,6 @@ qt3ds::runtime::IAnimationSystem &CPresentation::GetAnimationSystem() return *m_AnimationSystem; } -//============================================================================== /** * Simple manager access: Logic Manager */ @@ -702,7 +677,6 @@ ILogicSystem &CPresentation::GetLogicSystem() return *m_LogicSystem; } -//============================================================================== /** * Simple manager access: Params Manager */ @@ -736,7 +710,6 @@ qt3ds::foundation::IStringTable &CPresentation::GetStringTable() return GetApplication().GetRuntimeFactoryCore().GetStringTable(); } -//============================================================================== /** * Current frame data stores traversal lists for use later */ @@ -750,7 +723,6 @@ void CPresentation::SetLoadedBuffer(qt3ds::render::ILoadedBuffer &inBuffer) m_LoadedBuffer = inBuffer; } -//============================================================================== /** * Retrieve the name of the presentation. This is actually the file path. * @return the name of this presentation @@ -760,7 +732,6 @@ const QByteArray CPresentation::GetName() const return m_Name.toLatin1(); } -//============================================================================== /** * Retrieve the size of the presentation in Studio * @return the size of this presentation @@ -770,7 +741,6 @@ SPresentationSize CPresentation::GetSize() const return m_Size; } -//============================================================================== /** * Set the size of the presentation as reflected in Studio * @param inSize size of presentation ( width, height, scale mode ) in Studio diff --git a/src/Runtime/Source/runtime/Qt3DSPresentation.h b/src/Runtime/Source/runtime/Qt3DSPresentation.h index d813b418..5e3145fd 100644 --- a/src/Runtime/Source/runtime/Qt3DSPresentation.h +++ b/src/Runtime/Source/runtime/Qt3DSPresentation.h @@ -30,9 +30,6 @@ #pragma once -//============================================================================== -// Includes -//============================================================================== #include "RuntimePrefix.h" #include "Qt3DSIPresentation.h" #include "Qt3DSPresentationFrameData.h" @@ -53,6 +50,7 @@ Q_SIGNALS: void SigSlideEntered(const QString &elementPath, unsigned int index, const QString &name); void SigSlideExited(const QString &elementPath, unsigned int index, const QString &name); void SigCustomSignal(const QString &elementPath, const QString &name); + void SigMaterialCreated(const QString &name); }; namespace qt3ds { @@ -68,45 +66,40 @@ namespace render { } } -//============================================================================== -// Namespace -//============================================================================== namespace Q3DStudio { -//============================================================================== + /** * Intelligent representation of a Studio presentation. */ class CPresentation : public IPresentation { - //============================================================================== - // Fields - //============================================================================== protected: - QString m_Name; ///< Name of ths presentation - QString m_FilePath; ///< The full path from which this presentation was loaded - qt3ds::runtime::IApplication *m_Application; ///< Runtime object - IScene *m_Scene; ///< Connection to the associated scene (render) for this presentation - qt3ds::runtime::IActivityZone *m_ActivityZone; ///< Controls element active status. + QString m_Name; // Name of this presentation + QString m_FilePath; // Absolute path to this presentation + QString m_projectPath; // Absolute path to the project root + qt3ds::runtime::IApplication *m_Application; // Runtime object + IScene *m_Scene; // Connection to the associated scene (render) for this presentation + qt3ds::runtime::IActivityZone *m_ActivityZone; // Controls element active status TElement *m_RootElement; - CPresentationFrameData m_FrameData; ///< Storage of data of the current frame - CCircularArray<SEventCommand> m_EventCommandQueue; ///< The Event/Command integrated queue + CPresentationFrameData m_FrameData; // Storage of data of the current frame + CCircularArray<SEventCommand> m_EventCommandQueue; // The Event/Command integrated queue bool m_IsProcessingEventCommandQueue; - CEventCallbacks m_EventCallbacks; ///< Handles event callbacks on registered elements - SPresentationSize m_Size; ///< Native width, height and mode exported from Studio + CEventCallbacks m_EventCallbacks; // Handles event callbacks on registered elements + SPresentationSize m_Size; // Native width, height and mode exported from Studio qt3ds::foundation::NVScopedRefCounted<qt3ds::render::ILoadedBuffer> - m_LoadedBuffer; ///< Reference to loaded data when loading from binary. + m_LoadedBuffer; // Reference to loaded data when loading from binary CComponentManager m_ComponentManager; qt3ds::foundation::NVScopedRefCounted<ISlideSystem> - m_SlideSystem; ///< Container and factory of all logics + m_SlideSystem; // Container and factory of all slides qt3ds::foundation::NVScopedRefCounted<ILogicSystem> - m_LogicSystem; ///< Container and factory of all logics + m_LogicSystem; // Container and factory of all logics qt3ds::foundation::NVScopedRefCounted<IAnimationSystem> - m_AnimationSystem; ///< Container and factory of all animation tracks + m_AnimationSystem; // Container and factory of all animation tracks qt3ds::foundation::NVScopedRefCounted<IParametersSystem> - m_ParametersSystem; ///< Container and factory of all custom actions + m_ParametersSystem; // Container and factory of all custom actions TTimeUnit m_Offset; TTimeUnit m_LocalTime; @@ -118,12 +111,10 @@ protected: typedef eastl::hash_map<TElement *, qt3ds::foundation::CRegisteredString> TElemStringMap; TElemStringMap m_ElementPathMap; - //============================================================================== - // Methods - //============================================================================== public: // Construction - CPresentation(const CHAR *inName, qt3ds::runtime::IApplication *inRuntime); - virtual ~CPresentation(); + CPresentation(const QString &inName, const QString &projectPath, + qt3ds::runtime::IApplication *inRuntime); + virtual ~CPresentation() override; public: // Execution void Initialize(); @@ -153,11 +144,11 @@ public: // Bridge Control public: // Commands and Events void FireEvent(const SEventCommand &inEvent); void FireEvent(const TEventCommandHash inEventType, TElement *inTarget, - const UVariant *inArg1 = NULL, const UVariant *inArg2 = NULL, + const UVariant *inArg1 = nullptr, const UVariant *inArg2 = nullptr, const EAttributeType inType1 = ATTRIBUTETYPE_NONE, const EAttributeType inType2 = ATTRIBUTETYPE_NONE) override; void FireCommand(const TEventCommandHash inCommandType, TElement *inTarget, - const UVariant *inArg1 = NULL, const UVariant *inArg2 = NULL, + const UVariant *inArg1 = nullptr, const UVariant *inArg2 = nullptr, const EAttributeType inType1 = ATTRIBUTETYPE_NONE, const EAttributeType inType2 = ATTRIBUTETYPE_NONE) override; void FlushEventCommandQueue(void) override; @@ -213,9 +204,10 @@ public: // Configuration access void SetUpdateLock(const BOOL inLockUpdate); void SetVCAA(const BOOL inVCAA); -public: // Full file path +public: // Full file paths void SetFilePath(const CHAR *inPath) override; - QString GetFilePath() override; + QString GetFilePath() const override; + QString getProjectPath() const override; private: // Disabled Copy Construction CPresentation(CPresentation &); diff --git a/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp b/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp index e4aed96e..4825c7ef 100644 --- a/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp +++ b/src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp @@ -70,6 +70,13 @@ #include "Qt3DSRenderRuntimeBindingImpl.h" #include "Qt3DSRenderBufferManager.h" // TODO: Needed for adding meshes dynamically (QT3DS-3378) #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> @@ -357,8 +364,10 @@ struct SEmitSignalData : public NVRefCounted class CQmlEngineImpl : public CQmlEngine { - typedef NVScopedRefCounted<SEmitSignalData> TEmitSignalPtr; - typedef eastl::list<TEmitSignalPtr, ForwardingAllocator> TEmitSignalQueue; + 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; @@ -423,7 +432,10 @@ public: qt3ds::render::IQt3DSRenderer *renderer) override; void deleteElement(const QString &elementPath, qt3ds::render::IQt3DSRenderer *renderer) override; - //void createMaterial() override; // TODO (QT3DS-3377) + void createMaterial(const QString &elementPath, const QString &materialDefinition, + qt3ds::render::ICustomMaterialSystem *customMaterialSystem, + IDynamicObjectSystem *dynamicObjectSystem, + qt3ds::render::IQt3DSRenderer *renderer) override; //void createMesh() override; // TODO (QT3DS-3378) void GotoSlide(const char *component, const char *slideName, @@ -473,6 +485,39 @@ private: // 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); }; CQmlEngineImpl::CQmlEngineImpl(NVFoundationBase &fnd, ITimeProvider &) @@ -868,8 +913,7 @@ void CQmlEngineImpl::SetDataInputValue( } } -using TPropertyDescAndValueList = eastl::vector<qt3ds::runtime::element::TPropertyDescAndValue>; -using TPropertyDesc = qt3ds::runtime::element::SPropertyDesc; +static int _idCounter = 0; void CQmlEngineImpl::createElement(const QString &parentElementPath, const QString &slideName, const QHash<QString, QVariant> &properties, @@ -898,8 +942,7 @@ void CQmlEngineImpl::createElement(const QString &parentElementPath, const QStri IPresentation *presentation = parentElement->GetBelongedPresentation(); - static int idCounter = 0; - ++idCounter; + ++_idCounter; // Resolve slide QByteArray theSlideName = slideName.toUtf8(); @@ -921,7 +964,7 @@ void CQmlEngineImpl::createElement(const QString &parentElementPath, const QStri refMatName = QStringLiteral("/") + refMatName; if (newElementName.isEmpty()) - newElementName = QStringLiteral("NewElement_%1").arg(idCounter); + newElementName = QStringLiteral("NewElement_%1").arg(_idCounter); QByteArray newElementNameBa = newElementName.toUtf8(); // Make sure the name is not duplicate @@ -941,52 +984,6 @@ void CQmlEngineImpl::createElement(const QString &parentElementPath, const QStri const CRegisteredString elementSubType; TPropertyDescAndValueList elementProperties; - // Set properties - auto addStringAttribute = [&strTable](TPropertyDescAndValueList &list, - const QString &inAttName, const QString &inValue) { - QByteArray valueBa = inValue.toUtf8(); - qt3ds::foundation::CStringHandle strHandle = strTable.GetHandle(valueBa.constData()); - UVariant theValue; - theValue.m_StringHandle = strHandle.handle(); - const CRegisteredString attStr = strTable.RegisterStr(inAttName); - list.push_back( - eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_STRING), theValue)); - }; - auto addIntAttribute = [&strTable](TPropertyDescAndValueList &list, const QString &inAttName, - int inValue) { - UVariant theValue; - theValue.m_INT32 = inValue; - const CRegisteredString attStr = strTable.RegisterStr(inAttName); - list.push_back( - eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_INT32), theValue)); - }; - auto addBoolAttribute = [&strTable](TPropertyDescAndValueList &list, - const QString &inAttName, bool inValue) { - UVariant theValue; - theValue.m_INT32 = int(inValue); - const CRegisteredString attStr = strTable.RegisterStr(inAttName); - list.push_back( - eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_BOOL), theValue)); - }; - auto addFloatAttribute = [&strTable](TPropertyDescAndValueList &list, const QString &inAttName, - float inValue) { - UVariant theValue; - theValue.m_FLOAT = inValue; - const CRegisteredString attStr = strTable.RegisterStr(inAttName); - list.push_back( - eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_FLOAT), theValue)); - }; - auto addFloat3Attribute = [&strTable](TPropertyDescAndValueList &list, - const QStringList &inAttNames, const QVector3D &inValue) { - for (int i = 0; i < 3; ++i) { - UVariant theValue; - theValue.m_FLOAT = inValue[i]; - const CRegisteredString attStr = strTable.RegisterStr(inAttNames.at(i)); - list.push_back( - eastl::make_pair(TPropertyDesc(attStr, ATTRIBUTETYPE_FLOAT), theValue)); - } - }; - // Set default values for missing mandatory properties const QString sourcePathPropName = QStringLiteral("sourcepath"); const QString startTimePropName = QStringLiteral("starttime"); @@ -995,18 +992,20 @@ void CQmlEngineImpl::createElement(const QString &parentElementPath, const QStri Q3DStudio::UVariant attValue; bool eyeBall = true; theProperties.value(QStringLiteral("eyeball"), true).toBool(); - if (!theProperties.contains(sourcePathPropName)) - addStringAttribute(elementProperties, sourcePathPropName, QStringLiteral("#Cube")); + if (!theProperties.contains(sourcePathPropName)) { + addStringAttribute(strTable, elementProperties, sourcePathPropName, + QStringLiteral("#Cube")); + } if (!theProperties.contains(startTimePropName)) { parentElement->GetAttribute(Q3DStudio::ATTRIBUTE_STARTTIME, attValue); - addIntAttribute(elementProperties, startTimePropName, int(attValue.m_INT32)); + addIntAttribute(strTable, elementProperties, startTimePropName, int(attValue.m_INT32)); } if (!theProperties.contains(endTimePropName)) { parentElement->GetAttribute(Q3DStudio::ATTRIBUTE_ENDTIME, attValue); - addIntAttribute(elementProperties, endTimePropName, int(attValue.m_INT32)); + addIntAttribute(strTable, elementProperties, endTimePropName, int(attValue.m_INT32)); } if (!theProperties.contains(eyeBallPropName)) - addBoolAttribute(elementProperties, eyeBallPropName, true); + addBoolAttribute(strTable, elementProperties, eyeBallPropName, true); else eyeBall = theProperties.value(QStringLiteral("eyeball")).toBool(); @@ -1015,16 +1014,16 @@ void CQmlEngineImpl::createElement(const QString &parentElementPath, const QStri it.next(); switch (it.value().type()) { case QVariant::Double: - addFloatAttribute(elementProperties, it.key(), it.value().toFloat()); + addFloatAttribute(strTable, elementProperties, it.key(), it.value().toFloat()); break; case QVariant::Bool: - addBoolAttribute(elementProperties, it.key(), it.value().toBool()); + addBoolAttribute(strTable, elementProperties, it.key(), it.value().toBool()); break; case QVariant::Int: - addIntAttribute(elementProperties, it.key(), it.value().toInt()); + addIntAttribute(strTable, elementProperties, it.key(), it.value().toInt()); break; case QVariant::String: - addStringAttribute(elementProperties, it.key(), it.value().toString()); + addStringAttribute(strTable, elementProperties, it.key(), it.value().toString()); break; case QVariant::Vector3D: { QVector3D vec = it.value().value<QVector3D>(); @@ -1039,7 +1038,7 @@ void CQmlEngineImpl::createElement(const QString &parentElementPath, const QStri atts << (it.key() + QLatin1String(".x")) << (it.key() + QLatin1String(".y")) << (it.key() + QLatin1String(".z")); - addFloat3Attribute(elementProperties, atts, vec); + addFloat3Attribute(strTable, elementProperties, atts, vec); break; } default: @@ -1131,7 +1130,7 @@ void CQmlEngineImpl::createElement(const QString &parentElementPath, const QStri NVAllocatorCallback &allocator = presentation->GetScene()->allocator(); qt3ds::render::SModel *newObject = QT3DS_NEW(allocator, qt3ds::render::SModel)(); newObject->m_Id = strTable.RegisterStr((QByteArrayLiteral("_newObject_") - + QByteArray::number(idCounter)).constData()); + + QByteArray::number(_idCounter)).constData()); parentObject.AddChild(*newObject); qt3ds::render::Qt3DSTranslator::CreateTranslatorForElement(newElem, *newObject, allocator); @@ -1140,7 +1139,7 @@ void CQmlEngineImpl::createElement(const QString &parentElementPath, const QStri qt3ds::render::SReferencedMaterial *newMaterial = QT3DS_NEW(allocator, qt3ds::render::SReferencedMaterial)(); newMaterial->m_Id = strTable.RegisterStr((QByteArrayLiteral("_newMaterial_") - + QByteArray::number(idCounter)).constData()); + + QByteArray::number(_idCounter)).constData()); newMaterial->m_ReferencedMaterial = referencedMaterial; newObject->AddMaterial(*newMaterial); @@ -1236,6 +1235,336 @@ void CQmlEngineImpl::deleteElement(const QString &elementPath, m_Application->GetElementAllocator().ReleaseElement(*element, true); } +/** + Creates material into material container of the presentation that owns the specified element. + The materialDefinition parameter can contain a .materialdef file path or + the entire material definition in the .materialdef format. +*/ +void CQmlEngineImpl::createMaterial(const QString &elementPath, + const QString &materialDefinition, + ICustomMaterialSystem *customMaterialSystem, + IDynamicObjectSystem *dynamicObjectSystem, + qt3ds::render::IQt3DSRenderer *renderer) +{ + QByteArray thePath = elementPath.toUtf8(); + TElement *element = getTarget(thePath.constData()); + + if (!element) { + qWarning() << __FUNCTION__ << "Invalid element:" << elementPath; + return; + } + + CPresentation *presentation = static_cast<CPresentation *>(element->GetBelongedPresentation()); + QString presPath = QFileInfo(presentation->GetFilePath()).absolutePath(); + QString projPath = presentation->getProjectPath(); + + QString materialName; + QMap<QString, QString> materialProps; + QMap<QString, QMap<QString, QString>> textureProps; + + Q3DSMaterialDefinitionParser::getMaterialInfo(materialDefinition, + projPath, presPath, + materialName, materialProps, textureProps); + + // We don't care about the path parameter + const QString pathStr = QStringLiteral("path"); + if (materialProps.contains(pathStr)) + materialProps.remove(pathStr); + + // 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) { + // 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 == materialName) { + qWarning() << __FUNCTION__ << "Material already exists in material container"; + return; + } + nextChild = nextChild->GetSibling(); + } + } else { + // TODO: Create a material container if it doesn't exist (QT3DS-3412) + qWarning() << __FUNCTION__ << "Presentation has no material container"; + return; + } + + // Create material element in the container based on the material definition + auto &metaData = m_Application->GetMetaData(); + const auto matName = strTable.RegisterStr(materialName); + const bool isCustomMaterial + = materialProps.value(QStringLiteral("type")) == QLatin1String("CustomMaterial"); + CRegisteredString matType; + CRegisteredString matClass; + QHash<QString, qt3ds::render::dynamic::SPropertyDefinition> dynPropDefs; + + if (isCustomMaterial) { + CRegisteredString sourcePath + = strTable.RegisterStr(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 (materialProps.contains(propName)) + dynPropDefs.insert(propName, customProperties[i]); + } + } else { + qWarning() << __FUNCTION__ + << "Could not resolve material properties for CustomMaterial:" + << materialName; + } + } else { + qWarning() << __FUNCTION__ + << "Missing sourcepath from material definition of a CustomMaterial:" + << materialName; + } + } else { + matType = strTable.RegisterStr("Material"); + } + + auto createElementPropsFromDefProps = [&](const QMap<QString, QString> &defProps, + TPropertyDescAndValueList &elementProps, + const CRegisteredString &elementType) -> bool { + 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: + qWarning() << __FUNCTION__ + << "Unsupported material property type for property:" + << propIter.key(); + QT3DS_ASSERT(false); + break; + } + } + return true; + }; + + TPropertyDescAndValueList elementProps; + bool success = createElementPropsFromDefProps(materialProps, elementProps, matType); + if (!success) + return; // createElementPropsFromDefProps already prints a warning + + 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(textureProps); + QHash<QString, TElement *> imageElementMap; + while (texIter.hasNext()) { + texIter.next(); + elementProps.clear(); + success = createElementPropsFromDefProps(texIter.value(), elementProps, imageType); + if (!success) { + m_Application->GetElementAllocator().ReleaseElement(newMatElem, true); + return; // createElementPropsFromDefProps already prints a warning + } + 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("_newMaterial_") + 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 = 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: + qWarning() << __FUNCTION__ + << "Unsupported custom material property type '" << propDesc.m_DataType + << "' for property:" + << dynPropIter.key(); + QT3DS_ASSERT(false); + break; + } + } + } 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); + } + } + } + + qt3ds::render::Qt3DSTranslator::CreateTranslatorForElement(newMatElem, *newMaterial, allocator); + + // Notify presentation asynchronously to give renderer time to initialize the materials properly + QTimer::singleShot(0, [materialName, presentation]() { + presentation->signalProxy()->SigMaterialCreated(materialName); + }); +} + void CQmlEngineImpl::GotoSlide(const char *component, const char *slideName, const SScriptEngineGotoSlideArgs &inArgs) { @@ -1777,6 +2106,134 @@ QVector<QString> CQmlEngineImpl::resolveDependentDatainputs(const QString &expre 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; +} + +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 * @@ -1789,4 +2246,5 @@ CQmlEngine *CQmlEngine::Create(qt3ds::NVFoundationBase &inFoundation, ITimeProvi { return QT3DS_NEW(inFoundation.getAllocator(), CQmlEngineImpl)(inFoundation, inTimeProvider); } + } diff --git a/src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.cpp b/src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.cpp new file mode 100644 index 00000000..913a24ec --- /dev/null +++ b/src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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 "q3dsmaterialdefinitionparser.h" + +#include <QtCore/qfile.h> +#include <QtCore/qdir.h> +#include <QtCore/qxmlstream.h> +#include <QtCore/qtextstream.h> +#include <QtCore/qdebug.h> + +namespace Q3DStudio { + +void Q3DSMaterialDefinitionParser::getMaterialInfo(const QString &materialDefinition, + const QString &projPath, const QString &presPath, + QString &outName, QMap<QString, QString> &outValues, + QMap<QString, QMap<QString, QString>> &outTextureValues) +{ + // materialDefinition can be the .materialdef file name or its content + QString matDef; + if (materialDefinition.endsWith(QLatin1String(".materialdef"), Qt::CaseInsensitive)) { + QFile file(materialDefinition); + if (!file.open(QFile::Text | QFile::ReadOnly)) { + qWarning() << __FUNCTION__ << "Failed to open material definition file:" + << file.errorString(); + return; + } + QTextStream stream(&file); + matDef = stream.readAll(); + } else { + matDef = materialDefinition; + } + + QXmlStreamReader reader(matDef); + reader.setNamespaceProcessing(false); + + const QDir docDir(presPath); + const QDir projDir(projPath); + QString textureName; + QString propertyName; + QString propertyType; + QString propertyValue; + QMap<QString, QString> textureProperties; + + const QString matDataVersion = QStringLiteral("1.0"); + const QString sourcePathStr = QStringLiteral("sourcepath"); + const QString nameStr = QStringLiteral("name"); + const QString typeStr = QStringLiteral("type"); + const QString versionStr = QStringLiteral("version"); + + while (!reader.atEnd()) { + reader.readNext(); + if (reader.tokenType() == QXmlStreamReader::StartElement) { + if (reader.name() == QLatin1String("TextureData")) { + textureName = reader.attributes().value(nameStr).toString(); + textureProperties.clear(); + } else if (reader.name() == QLatin1String("Property")) { + propertyName = reader.attributes().value(nameStr).toString(); + propertyType = reader.attributes().value(typeStr).toString(); + propertyValue.clear(); + } else if (reader.name() == QLatin1String("MaterialData")) { + QString version = reader.attributes().value(versionStr).toString(); + if (version != matDataVersion) { + qWarning() << __FUNCTION__ << "Invalid MaterialData version; expected '" + << matDataVersion << "', got '" << version << "'"; + outName.clear(); + outValues.clear(); + outTextureValues.clear(); + return; + } + } + } else if (reader.tokenType() == QXmlStreamReader::EndElement) { + if (reader.name() == QLatin1String("TextureData")) { + outTextureValues[textureName] = textureProperties; + textureName.clear(); + } else if (reader.name() == QLatin1String("Property")) { + if (textureName.isEmpty()) { + outValues[propertyName] = propertyValue; + if (propertyName == nameStr) + outName = propertyValue; + } else { + textureProperties[propertyName] = propertyValue; + } + propertyName.clear(); + propertyType.clear(); + } + } else if (reader.tokenType() == QXmlStreamReader::Characters) { + if (!propertyName.isEmpty()) { + propertyValue = reader.text().toString(); + if (propertyName == sourcePathStr) { + // Check that the referenced file exists + const auto absSourcePath = projDir.absoluteFilePath(propertyValue); + if (!QFileInfo(absSourcePath).exists()) { + qWarning() << __FUNCTION__ << "Referenced file doesn't exist:" + << propertyValue; + outName.clear(); + outValues.clear(); + outTextureValues.clear(); + return; + } + } + if (!propertyValue.isEmpty() && (propertyType == QLatin1String("Texture") + || propertyName == sourcePathStr)) { + propertyValue = docDir.relativeFilePath( + projDir.absoluteFilePath(propertyValue)); + } + } + } + } +} + +} diff --git a/src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.h b/src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.h new file mode 100644 index 00000000..f6d98bbf --- /dev/null +++ b/src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.h @@ -0,0 +1,49 @@ +/**************************************************************************** +** +** Copyright (C) 2019 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$ +** +****************************************************************************/ + +#ifndef Q3DSMATERIALDEFINITIONPARSER_H +#define Q3DSMATERIALDEFINITIONPARSER_H + +#include <QtCore/qstring.h> +#include <QtCore/qmap.h> + +namespace Q3DStudio { + +class Q3DSMaterialDefinitionParser +{ +public: + static void getMaterialInfo(const QString &materialDefinition, + const QString &projPath, const QString &presPath, + QString &outName, QMap<QString, QString> &outValues, + QMap<QString, QMap<QString, QString>> &outTextureValues); +}; + +} + +#endif diff --git a/src/Runtime/Source/uipparser/Qt3DSIPresentation.h b/src/Runtime/Source/uipparser/Qt3DSIPresentation.h index 00f3d15a..a9d36446 100644 --- a/src/Runtime/Source/uipparser/Qt3DSIPresentation.h +++ b/src/Runtime/Source/uipparser/Qt3DSIPresentation.h @@ -30,9 +30,6 @@ #pragma once -//============================================================================== -// Includes -//============================================================================== #include "Qt3DSEventCallbacks.h" namespace qt3ds { @@ -52,14 +49,8 @@ namespace foundation { } } -//============================================================================== -// Namespace -//============================================================================== namespace Q3DStudio { -//============================================================================== -// Forwards -//============================================================================== class IComponentManager; class IEventManager; class IScene; @@ -71,20 +62,14 @@ using qt3ds::runtime::IAnimationSystem; using qt3ds::runtime::ILogicSystem; using qt3ds::runtime::IParametersSystem; -//============================================================================== -// Enumeration -//============================================================================== -/// Method used to translate from presentation size to window size +// Method used to translate from presentation size to window size enum EScaleMode { - SCALEMODE_FREE, ///< Free scaling mode - SCALEMODE_EXACT, ///< Fixed presentation size - SCALEMODE_ASPECT, ///< Maintain aspect ratio - SCALEMODE_UNKNOWN, ///< ERROR! - Uninitialized scale mode + SCALEMODE_FREE, // Free scaling mode + SCALEMODE_EXACT, // Fixed presentation size + SCALEMODE_ASPECT, // Maintain aspect ratio + SCALEMODE_UNKNOWN, // ERROR! - Uninitialized scale mode }; -//============================================================================== -// Structs -//============================================================================== struct SPresentationSize { SPresentationSize() @@ -93,22 +78,18 @@ struct SPresentationSize , m_ScaleMode(0) { } - UINT16 m_Width; ///< Native width of the presentation - UINT16 m_Height; ///< Native height of the presentation - UINT8 m_ScaleMode; ///< Presentation to window scale method + UINT16 m_Width; // Native width of the presentation + UINT16 m_Height; // Native height of the presentation + UINT8 m_ScaleMode; // Presentation to window scale method UINT8 m_Padding[3]; }; -//============================================================================== /** * @interface IPresentation * Base interface of the presentation. */ class IPresentation { - //============================================================================== - // Methods - //============================================================================== public: // Construction IPresentation() {} virtual ~IPresentation() {} @@ -127,11 +108,11 @@ public: // Bridge Control public: // Commands and Events virtual void FireEvent(const TEventCommandHash inEventType, TElement *inTarget, - const UVariant *inArg1 = NULL, const UVariant *inArg2 = NULL, + const UVariant *inArg1 = nullptr, const UVariant *inArg2 = nullptr, const EAttributeType inType1 = ATTRIBUTETYPE_NONE, const EAttributeType inType2 = ATTRIBUTETYPE_NONE) = 0; virtual void FireCommand(const TEventCommandHash inEventType, TElement *inTarget, - const UVariant *inArg1 = NULL, const UVariant *inArg2 = NULL, + const UVariant *inArg1 = nullptr, const UVariant *inArg2 = nullptr, const EAttributeType inType1 = ATTRIBUTETYPE_NONE, const EAttributeType inType2 = ATTRIBUTETYPE_NONE) = 0; virtual void FlushEventCommandQueue(void) = 0; @@ -153,7 +134,8 @@ public: // Hooks and callbacks public: // Full file path virtual void SetFilePath(const CHAR *inPath) = 0; - virtual QString GetFilePath() = 0; + virtual QString GetFilePath() const = 0; + virtual QString getProjectPath() const = 0; virtual TElement *GetRoot() = 0; virtual void SetRoot(TElement &inRoot) = 0; diff --git a/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp b/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp index 8bf7eb80..fadd680c 100644 --- a/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp +++ b/src/Runtime/Source/viewer/Qt3DSViewerApp.cpp @@ -357,6 +357,8 @@ bool Q3DSViewerApp::InitializeApp(int winWidth, int winHeight, const QSurfaceFor &QRuntimeViewSignalProxy::SigSlideExited, this, &Q3DSViewerApp::SigSlideExited); connect(m_Impl.m_view->signalProxy(), &QRuntimeViewSignalProxy::SigCustomSignal, this, &Q3DSViewerApp::SigCustomSignal); + connect(m_Impl.m_view->signalProxy(), &QRuntimeViewSignalProxy::SigMaterialCreated, this, + &Q3DSViewerApp::SigMaterialCreated); Resize(winWidth, winHeight); @@ -811,6 +813,14 @@ void Q3DSViewerApp::deleteElement(const QString &elementPath) m_Impl.m_view->deleteElement(elementPath); } +void Q3DSViewerApp::createMaterial(const QString &elementPath, const QString &materialDefinition) +{ + if (!m_Impl.m_view) + return; + + m_Impl.m_view->createMaterial(elementPath, materialDefinition); +} + Q3DSViewerApp &Q3DSViewerApp::Create(void *glContext, Q3DStudio::IAudioPlayer *inAudioPlayer, QElapsedTimer *startupTimer) { diff --git a/src/Runtime/Source/viewer/Qt3DSViewerApp.h b/src/Runtime/Source/viewer/Qt3DSViewerApp.h index d2d9b93e..5cd52bca 100644 --- a/src/Runtime/Source/viewer/Qt3DSViewerApp.h +++ b/src/Runtime/Source/viewer/Qt3DSViewerApp.h @@ -362,6 +362,7 @@ public: void createElement(const QString &parentElementPath, const QString &slideName, const QHash<QString, QVariant> &properties); void deleteElement(const QString &elementPath); + void createMaterial(const QString &elementPath, const QString &materialDefinition); QString error(); @@ -403,6 +404,7 @@ Q_SIGNALS: void SigSlideEntered(const QString &elementPath, unsigned int index, const QString &name); void SigSlideExited(const QString &elementPath, unsigned int index, const QString &name); void SigCustomSignal(const QString &elementPath, const QString &name); + void SigMaterialCreated(const QString &name); void SigPresentationReady(); }; |