summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiikka Heikkinen <miikka.heikkinen@qt.io>2019-05-03 17:32:41 +0300
committerMiikka Heikkinen <miikka.heikkinen@qt.io>2019-05-14 12:02:22 +0000
commit0a82b82de3ad7796cf91a355017a24ace2c830b4 (patch)
tree431464639e01b1e8313b420c33dbdcc7fbd4683b
parentd34ae2ca1590c063e26bd294c26accd9e8b605a1 (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>
-rw-r--r--src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp93
-rw-r--r--src/Runtime/Qt3DSRuntimeStatic/Qt3DSRuntimeStatic.pro2
-rw-r--r--src/Runtime/Source/engine/Qt3DSRuntimeView.cpp16
-rw-r--r--src/Runtime/Source/engine/Qt3DSRuntimeView.h2
-rw-r--r--src/Runtime/Source/runtime/Qt3DSApplication.cpp4
-rw-r--r--src/Runtime/Source/runtime/Qt3DSIScriptBridge.h6
-rw-r--r--src/Runtime/Source/runtime/Qt3DSPresentation.cpp80
-rw-r--r--src/Runtime/Source/runtime/Qt3DSPresentation.h58
-rw-r--r--src/Runtime/Source/runtime/Qt3DSQmlEngine.cpp590
-rw-r--r--src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.cpp138
-rw-r--r--src/Runtime/Source/runtime/q3dsmaterialdefinitionparser.h49
-rw-r--r--src/Runtime/Source/uipparser/Qt3DSIPresentation.h42
-rw-r--r--src/Runtime/Source/viewer/Qt3DSViewerApp.cpp10
-rw-r--r--src/Runtime/Source/viewer/Qt3DSViewerApp.h2
-rw-r--r--src/Viewer/qmlviewer/Qt3DSRenderer.cpp8
-rw-r--r--src/Viewer/qmlviewer/Qt3DSRenderer.h2
-rw-r--r--src/Viewer/qmlviewer/Qt3DSView.cpp4
-rw-r--r--src/Viewer/studio3d/q3dscommandqueue.cpp1
-rw-r--r--src/Viewer/studio3d/q3dscommandqueue_p.h1
-rw-r--r--src/Viewer/studio3d/q3dspresentation.cpp40
-rw-r--r--src/Viewer/studio3d/q3dspresentation.h2
-rw-r--r--tests/auto/viewer/tst_qt3dsviewer.cpp182
-rw-r--r--tests/auto/viewer/tst_qt3dsviewer.h7
-rw-r--r--tests/auto/viewer/tst_qt3dsviewer.qml2
-rw-r--r--tests/auto/viewer/viewer.qrc7
-rw-r--r--tests/scenes/simple_cube_animation/maps/QT-symbol.pngbin0 -> 4541 bytes
-rw-r--r--tests/scenes/simple_cube_animation/maps/materials/shadow.pngbin0 -> 334 bytes
-rw-r--r--tests/scenes/simple_cube_animation/maps/materials/spherical_checker.pngbin0 -> 11066 bytes
-rw-r--r--tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef25
-rw-r--r--tests/scenes/simple_cube_animation/materials/Basic Green.materialdef6
-rw-r--r--tests/scenes/simple_cube_animation/materials/Basic Red.materialdef6
-rw-r--r--tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef63
-rw-r--r--tests/scenes/simple_cube_animation/materials/Copper.materialdef14
-rw-r--r--tests/scenes/simple_cube_animation/materials/copper.shader178
-rw-r--r--tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip20
35 files changed, 1330 insertions, 330 deletions
diff --git a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
index b821701d..71dc1de1 100644
--- a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
@@ -86,6 +86,7 @@
#include <QtCore/qdir.h>
#include <unordered_set>
#include "runtime/q3dsqmlbehavior.h"
+#include "runtime/q3dsmaterialdefinitionparser.h"
#include "Qt3DSFileToolsSeekableMeshBufIOStream.h"
#include "IObjectReferenceHelper.h"
#include "StudioProjectSettings.h"
@@ -917,93 +918,13 @@ public:
QString &outName, QMap<QString, QString> &outValues,
QMap<QString, QMap<QString, QString>> &outTextureValues) override
{
- if (!QFileInfo(inAbsoluteFilePath).exists())
- return;
-
- qt3ds::foundation::CFileSeekableIOStream theStream(inAbsoluteFilePath,
- qt3ds::foundation::FileReadFlags());
- if (theStream.IsOpen()) {
- const QDir docDir(m_Doc.GetDocumentDirectory().toQString());
- const QDir projDir = g_StudioApp.GetCore()->getProjectFile().getProjectPath();
+ Q3DStudio::Q3DSMaterialDefinitionParser::getMaterialInfo(
+ inAbsoluteFilePath, g_StudioApp.GetCore()->getProjectFile().getProjectPath(),
+ m_Doc.GetDocumentDirectory().toQString(), outName, outValues, outTextureValues);
- std::shared_ptr<IDOMFactory> theFactory =
- IDOMFactory::CreateDOMFactory(m_DataCore.GetStringTablePtr());
- SImportXmlErrorHandler theImportHandler(m_Doc.GetImportFailedHandler(),
- Q3DStudio::CString::fromQString(
- inAbsoluteFilePath));
- qt3dsdm::SDOMElement *theElem =
- CDOMSerializer::Read(*theFactory, theStream, &theImportHandler);
- if (theElem) {
- outName = getMaterialNameFromFilePath(inAbsoluteFilePath);
- std::shared_ptr<IDOMReader> theReader = IDOMReader::CreateDOMReader(
- *theElem, m_DataCore.GetStringTablePtr(), theFactory);
-
- const QString sourcePath = QStringLiteral("sourcepath");
- QStringList convertPaths;
- for (bool success = theReader->MoveToFirstChild("Property"); success;
- success = theReader->MoveToNextSibling("Property")) {
- const char8_t *name = "";
- const char8_t *value = "";
- const char8_t *type = "";
- theReader->Att("name", name);
- theReader->Att("type", type);
- theReader->Value(value);
- const QString nameStr = QString::fromUtf8(name);
- const QString valueStr = QString::fromUtf8(value);
- if (nameStr == sourcePath) {
- // Check if the custom material still exists
- const auto absSourcePath = projDir.absoluteFilePath(valueStr);
- if (!QFileInfo(absSourcePath).exists()) {
- outValues.clear();
- outTextureValues.clear();
- return;
- }
- }
- if (!valueStr.isEmpty() && (QString::fromUtf8(type) == QLatin1String("Texture")
- || nameStr == sourcePath)) {
- convertPaths.append(nameStr);
- }
- outValues[nameStr] = valueStr;
- }
-
- for (const auto &prop : qAsConst(convertPaths)) {
- // Change paths to be relative to the presentation
- const QString origPath = outValues[prop];
- outValues[prop] = docDir.relativeFilePath(projDir.absoluteFilePath(origPath));
- }
-
- if (AreEqual(theReader->GetElementName(), L"Property"))
- theReader->Leave();
-
- for (bool texSuccess = theReader->MoveToFirstChild("TextureData"); texSuccess;
- texSuccess = theReader->MoveToNextSibling("TextureData")) {
- QMap<QString, QString> texValues;
- const char8_t *texName = "";
- theReader->Att("name", texName);
- for (bool success = theReader->MoveToFirstChild("Property"); success;
- success = theReader->MoveToNextSibling("Property")) {
- const char8_t *name = "";
- const char8_t *value = "";
- theReader->Att("name", name);
- theReader->Value(value);
- texValues[name] = value;
- }
-
- if (texValues.contains(sourcePath) && !texValues[sourcePath].isEmpty()) {
- // Change path to be relative to the presentation
- texValues[sourcePath] = docDir.relativeFilePath(
- projDir.absoluteFilePath(texValues[sourcePath]));
- }
-
- outTextureValues[texName] = texValues;
-
- if (AreEqual(theReader->GetElementName(), L"Property"))
- theReader->Leave();
- }
-
- outValues[QStringLiteral("name")] = outName;
- }
- }
+ // Fix the outName to follow the file name (in case it has changed)
+ outName = getMaterialNameFromFilePath(inAbsoluteFilePath);
+ outValues[QStringLiteral("name")] = outName;
}
///////////////////////////////////////////////////////////////////
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();
};
diff --git a/src/Viewer/qmlviewer/Qt3DSRenderer.cpp b/src/Viewer/qmlviewer/Qt3DSRenderer.cpp
index 73e2f0f8..4122a645 100644
--- a/src/Viewer/qmlviewer/Qt3DSRenderer.cpp
+++ b/src/Viewer/qmlviewer/Qt3DSRenderer.cpp
@@ -207,6 +207,10 @@ bool Q3DSRenderer::initializeRuntime(QOpenGLFramebufferObject *inFbo)
this, &Q3DSRenderer::enterSlide);
connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigSlideExited,
this, &Q3DSRenderer::exitSlide);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal,
+ this, &Q3DSRenderer::customSignalEmitted);
+ connect(m_runtime, &Q3DSViewer::Q3DSViewerApp::SigMaterialCreated,
+ this, &Q3DSRenderer::materialCreated);
return true;
}
@@ -342,6 +346,10 @@ void Q3DSRenderer::processCommands()
m_runtime->deleteElement(cmd.m_elementPath);
break;
}
+ case CommandType_CreateMaterial: {
+ m_runtime->createMaterial(cmd.m_elementPath, cmd.m_stringValue);
+ break;
+ }
case CommandType_RequestSlideInfo: {
int current = 0;
int previous = 0;
diff --git a/src/Viewer/qmlviewer/Qt3DSRenderer.h b/src/Viewer/qmlviewer/Qt3DSRenderer.h
index 86bb59c1..2d3b69db 100644
--- a/src/Viewer/qmlviewer/Qt3DSRenderer.h
+++ b/src/Viewer/qmlviewer/Qt3DSRenderer.h
@@ -61,6 +61,8 @@ Q_SIGNALS:
void exitSlide(const QString &elementPath, unsigned int slide, const QString &slideName);
void requestResponse(const QString &elementPath, CommandType commandType, void *requestData);
void presentationReady();
+ void customSignalEmitted(const QString &elementPath, const QString &name);
+ void materialCreated(const QString &name);
protected:
static void onInitHandler(void *userData);
diff --git a/src/Viewer/qmlviewer/Qt3DSView.cpp b/src/Viewer/qmlviewer/Qt3DSView.cpp
index f5abb3e1..a68bd667 100644
--- a/src/Viewer/qmlviewer/Qt3DSView.cpp
+++ b/src/Viewer/qmlviewer/Qt3DSView.cpp
@@ -205,6 +205,10 @@ QQuickFramebufferObject::Renderer *Q3DSView::createRenderer() const
m_presentation->d_ptr, &Q3DSPresentationPrivate::handleSlideEntered);
connect(renderer, &Q3DSRenderer::exitSlide,
m_presentation, &Q3DSPresentation::slideExited);
+ connect(renderer, &Q3DSRenderer::customSignalEmitted,
+ m_presentation, &Q3DSPresentation::customSignalEmitted);
+ connect(renderer, &Q3DSRenderer::materialCreated,
+ m_presentation, &Q3DSPresentation::materialCreated);
connect(renderer, &Q3DSRenderer::requestResponse,
this, &Q3DSView::requestResponseHandler);
connect(renderer, &Q3DSRenderer::presentationReady,
diff --git a/src/Viewer/studio3d/q3dscommandqueue.cpp b/src/Viewer/studio3d/q3dscommandqueue.cpp
index c6f636e3..ed0ad8b5 100644
--- a/src/Viewer/studio3d/q3dscommandqueue.cpp
+++ b/src/Viewer/studio3d/q3dscommandqueue.cpp
@@ -217,6 +217,7 @@ void CommandQueue::copyCommands(CommandQueue &fromQueue)
break;
case CommandType_GoToSlideByName:
case CommandType_FireEvent:
+ case CommandType_CreateMaterial:
queueCommand(source.m_elementPath, source.m_commandType, source.m_stringValue);
break;
case CommandType_SetPresentationActive:
diff --git a/src/Viewer/studio3d/q3dscommandqueue_p.h b/src/Viewer/studio3d/q3dscommandqueue_p.h
index 43b7ef89..ff30829f 100644
--- a/src/Viewer/studio3d/q3dscommandqueue_p.h
+++ b/src/Viewer/studio3d/q3dscommandqueue_p.h
@@ -70,6 +70,7 @@ enum CommandType {
CommandType_SetDataInputValue,
CommandType_CreateElement,
CommandType_DeleteElement,
+ CommandType_CreateMaterial,
// Requests
CommandType_RequestSlideInfo,
diff --git a/src/Viewer/studio3d/q3dspresentation.cpp b/src/Viewer/studio3d/q3dspresentation.cpp
index 6884e0ee..3739ae66 100644
--- a/src/Viewer/studio3d/q3dspresentation.cpp
+++ b/src/Viewer/studio3d/q3dspresentation.cpp
@@ -36,9 +36,7 @@
#include <QtCore/qdebug.h>
#include <QtCore/qsettings.h>
#include <QtCore/qcoreapplication.h>
-#include <QtGui/QKeyEvent>
-#include <QtGui/QMouseEvent>
-#include <QtGui/QWheelEvent>
+#include <QtGui/qevent.h>
QT_BEGIN_NAMESPACE
@@ -276,11 +274,11 @@ void Q3DSPresentation::setDataInputValue(const QString &name, const QVariant &va
}
/**
- Adds a new child element for the element specified by parentElementPath to the slide specified with
- slideName. Only model element creation is currently supported.
- A referenced material element is also created for the new model element. The source material name
- can be specified with custom "material" property in the properties hash.
- The source material must exist in the material container of the presentation.
+ Adds a new child element for the element specified by parentElementPath to the slide specified
+ with slideName. Only model element creation is currently supported.
+ A referenced material element is also created for the new model element. The source material
+ name can be specified with custom "material" property in the properties hash.
+ The source material must exist in the material container of the presentation.
*/
void Q3DSPresentation::createElement(const QString &parentElementPath, const QString &slideName,
const QHash<QString, QVariant> &properties)
@@ -296,8 +294,8 @@ void Q3DSPresentation::createElement(const QString &parentElementPath, const QSt
}
/**
- Removes an element added by createElement and all its child elements.
- */
+ Removes an element added by createElement and all its child elements.
+*/
void Q3DSPresentation::deleteElement(const QString &elementPath)
{
if (d_ptr->m_viewerApp)
@@ -306,6 +304,24 @@ void Q3DSPresentation::deleteElement(const QString &elementPath)
d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_DeleteElement);
}
+/**
+ Creates a material specified by the materialDefinition parameter into the material
+ container of the presentation that owns the element specified by the elementPath parameter.
+ After creation, the material can be used for new elements created via createElement.
+ The materialDefinition parameter can contain either the file path to a material definition
+ file or a material definition in the Qt 3D Studion material data format.
+*/
+void Q3DSPresentation::createMaterial(const QString &elementPath,
+ const QString &materialDefinition)
+{
+ if (d_ptr->m_viewerApp) {
+ d_ptr->m_viewerApp->createMaterial(elementPath, materialDefinition);
+ } else if (d_ptr->m_commandQueue) {
+ d_ptr->m_commandQueue->queueCommand(elementPath, CommandType_CreateMaterial,
+ materialDefinition);
+ }
+}
+
void Q3DSPresentation::mousePressEvent(QMouseEvent *e)
{
if (d_ptr->m_viewerApp) {
@@ -448,6 +464,8 @@ void Q3DSPresentationPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app, bool
q_ptr, &Q3DSPresentation::slideExited);
connect(app, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal,
q_ptr, &Q3DSPresentation::customSignalEmitted);
+ connect(app, &Q3DSViewer::Q3DSViewerApp::SigMaterialCreated,
+ q_ptr, &Q3DSPresentation::materialCreated);
}
if (oldApp) {
disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigSlideEntered,
@@ -456,6 +474,8 @@ void Q3DSPresentationPrivate::setViewerApp(Q3DSViewer::Q3DSViewerApp *app, bool
q_ptr, &Q3DSPresentation::slideExited);
disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigCustomSignal,
q_ptr, &Q3DSPresentation::customSignalEmitted);
+ disconnect(oldApp, &Q3DSViewer::Q3DSViewerApp::SigMaterialCreated,
+ q_ptr, &Q3DSPresentation::materialCreated);
}
}
}
diff --git a/src/Viewer/studio3d/q3dspresentation.h b/src/Viewer/studio3d/q3dspresentation.h
index 97017008..b444f008 100644
--- a/src/Viewer/studio3d/q3dspresentation.h
+++ b/src/Viewer/studio3d/q3dspresentation.h
@@ -86,6 +86,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);
public Q_SLOTS:
void setSource(const QUrl &source);
@@ -112,6 +113,7 @@ Q_SIGNALS:
void dataInputsReady();
void customSignalEmitted(const QString &elementPath, const QString &name);
void delayedLoadingChanged(bool enable);
+ void materialCreated(const QString &name);
private:
Q_DISABLE_COPY(Q3DSPresentation)
diff --git a/tests/auto/viewer/tst_qt3dsviewer.cpp b/tests/auto/viewer/tst_qt3dsviewer.cpp
index f7d5e831..d3387678 100644
--- a/tests/auto/viewer/tst_qt3dsviewer.cpp
+++ b/tests/auto/viewer/tst_qt3dsviewer.cpp
@@ -34,6 +34,9 @@
#include <QtStudio3D/Q3DSElement>
#include <QtStudio3D/Q3DSViewerSettings>
#include <QtCore/QRandomGenerator>
+#include <QtCore/QFile>
+#include <QtCore/QTextStream>
+#include <QtCore/QRegularExpression>
void messageOutput(QtMsgType type, const QMessageLogContext &context,
const QString &msg)
@@ -98,6 +101,7 @@ void tst_qt3dsviewer::init()
void tst_qt3dsviewer::cleanup()
{
+ deleteCreatedElements(0);
m_viewer.hide();
}
@@ -165,7 +169,8 @@ void tst_qt3dsviewer::testSettings()
void tst_qt3dsviewer::testCreateElement()
{
- // Currently this method is very bare bones on actual testing.
+ // Currently this method is very bare bones on actual testing due to lack of programmatic
+ // feedback on dynamic object creation.
// It can be used to visually check if items are getting created.
m_viewer.show();
@@ -187,7 +192,7 @@ void tst_qt3dsviewer::testCreateElement()
QVariant::fromValue<QVector3D>(QVector3D(200, 300, 200)));
data.insert(QStringLiteral("opacity"), 20.0);
- m_presentation->createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
// Elements can be registered before they are created
Q3DSElement newCylinder(m_presentation, QStringLiteral("Scene.Layer.New Cylinder"));
@@ -218,8 +223,8 @@ void tst_qt3dsviewer::testCreateElement()
data.insert(QStringLiteral("position"),
QVariant::fromValue<QVector3D>(QVector3D(50, animValue, 50)));
- m_presentation->createElement(QStringLiteral("Scene.Layer.New Cylinder"),
- QStringLiteral("Slide1"), data);
+ createElement(QStringLiteral("Scene.Layer.New Cylinder"),
+ QStringLiteral("Slide1"), data);
data.clear();
data.insert(QStringLiteral("name"), QStringLiteral("New Sphere"));
@@ -230,8 +235,7 @@ void tst_qt3dsviewer::testCreateElement()
data.insert(QStringLiteral("position"),
QVariant::fromValue<QVector3D>(QVector3D(animValue, 75, 0)));
- m_presentation->createElement(QStringLiteral("Scene.Layer.Cube2"),
- QStringLiteral("Slide2"), data);
+ createElement(QStringLiteral("Scene.Layer.Cube2"), QStringLiteral("Slide2"), data);
data.clear();
data.insert(QStringLiteral("name"), QStringLiteral("Sphere To Delete"));
@@ -242,8 +246,7 @@ void tst_qt3dsviewer::testCreateElement()
data.insert(QStringLiteral("position"),
QVariant::fromValue<QVector3D>(QVector3D(-100, -100, 0)));
- m_presentation->createElement(QStringLiteral("Scene.Layer"),
- QStringLiteral("Slide2"), data);
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide2"), data);
animationTimer.start();
});
@@ -254,6 +257,8 @@ void tst_qt3dsviewer::testCreateElement()
// Remove dynamically added object
QTimer::singleShot(3000, [&]() {
m_presentation->deleteElement(QStringLiteral("Scene.Layer.Sphere To Delete"));
+ // Don't remove the deleted element from createdElements to test removing already deleted
+ // element later when everything is cleaned up.
});
// Create objects to slides 1 and 2 while slide 2 is executing
@@ -267,8 +272,7 @@ void tst_qt3dsviewer::testCreateElement()
data.insert(QStringLiteral("position"),
QVariant::fromValue<QVector3D>(QVector3D(-100, -100, 0)));
- m_presentation->createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"),
- data);
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
data.clear();
data.insert(QStringLiteral("name"), QStringLiteral("New Sphere 2"));
@@ -279,8 +283,7 @@ void tst_qt3dsviewer::testCreateElement()
data.insert(QStringLiteral("position"),
QVariant::fromValue<QVector3D>(QVector3D(-100, 100, 0)));
- m_presentation->createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide2"),
- data);
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide2"), data);
});
// Switch to slide 1
@@ -290,16 +293,14 @@ void tst_qt3dsviewer::testCreateElement()
createTimer.setInterval(0);
static int elemCounter = 0;
QRandomGenerator rnd;
- QStringList massModels;
- auto createModelsConnection = QObject::connect(&createTimer, &QTimer::timeout, [&]() {
- // Create a bunch of models to slide 2 in small batches to avoid slowdown
+ auto createElementsConnection = QObject::connect(&createTimer, &QTimer::timeout, [&]() {
+ // Create a bunch of elements to slide 2 in small batches to avoid slowdown
for (int i = 0; i < 5; ++i) {
++elemCounter;
data.clear();
- QString modelName = QStringLiteral("MassModel_%1").arg(elemCounter);
- massModels << QStringLiteral("Scene.Layer.") + modelName;
- data.insert(QStringLiteral("name"), modelName);
+ QString elementName = QStringLiteral("MassElement_%1").arg(elemCounter);
+ data.insert(QStringLiteral("name"), elementName);
data.insert(QStringLiteral("sourcepath"),
elemCounter % 2 ? QStringLiteral("#Cube") : QStringLiteral("#Cone"));
data.insert(QStringLiteral("material"),
@@ -310,39 +311,152 @@ void tst_qt3dsviewer::testCreateElement()
rnd.bounded(-600, 600),
rnd.bounded(800, 1200))));
- m_presentation->createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide2"),
- data);
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide2"), data);
}
if (elemCounter >= 1000) {
- qDebug() << "Extra models created:" << elemCounter;
+ qDebug() << "Extra elements created:" << elemCounter;
createTimer.stop();
}
});
- qDebug() << "Start creating extra models";
+ qDebug() << "Start creating extra elements";
createTimer.start();
// Switch to slide 2
QVERIFY(spyExited.wait(20000));
- QObject::disconnect(createModelsConnection);
+ QObject::disconnect(createElementsConnection);
QTest::qWait(500);
- elemCounter = massModels.size() - 1;
- QObject::connect(&createTimer, &QTimer::timeout, [&]() {
- // Delete all models we created previously
+ deleteCreatedElements(1);
+
+ // Switch to slide 1
+ QVERIFY(spyExited.wait(20000));
+ QTest::qWait(1000);
+}
+
+void tst_qt3dsviewer::testCreateMaterial()
+{
+ m_viewer.show();
+
+ m_settings->setShowRenderStats(true);
+ m_settings->setScaleMode(Q3DSViewerSettings::ScaleModeFill);
+
+ QSignalSpy spyExited(m_presentation,
+ SIGNAL(slideExited(const QString &, unsigned int, const QString &)));
+ QSignalSpy spyMatCreated(m_presentation, SIGNAL(materialCreated(const QString &)));
+
+ // Create material via .materialdef file in resources
+ m_presentation->createMaterial(
+ QStringLiteral("Scene"),
+ QStringLiteral(
+ ":/scenes/simple_cube_animation/materials/Basic Blue.materialdef"));
+ m_presentation->createMaterial(
+ QStringLiteral("Scene"),
+ QStringLiteral(
+ ":/scenes/simple_cube_animation/materials/Basic Texture.materialdef"));
+
+ // Create material directly from materialdef content
+ auto loadMatDefFile = [&](const QString &fileName) -> QString {
+ QFile matDefFile(fileName);
+ if (!matDefFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return {};
+
+ QTextStream in(&matDefFile);
+ return in.readAll();
+ };
+ QString matDef = loadMatDefFile(
+ QStringLiteral(":/scenes/simple_cube_animation/materials/Copper.materialdef"));
+ QVERIFY(!matDef.isEmpty());
+
+ m_presentation->createMaterial(QStringLiteral("Scene"), matDef);
+
+ QObject::connect(m_presentation, &Q3DSPresentation::materialCreated,
+ [this](const QString &name) {
+ QHash<QString, QVariant> data;
+
+ if (name == QStringLiteral("materials/Basic Blue")) {
+ data.insert(QStringLiteral("name"), QStringLiteral("Blue Cylinder"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cylinder"));
+ data.insert(QStringLiteral("material"), name);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(200, 300, 200)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ }
+
+ if (name == QStringLiteral("materials/Basic Texture")) {
+ data.insert(QStringLiteral("name"), QStringLiteral("Textured Cone"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cone"));
+ data.insert(QStringLiteral("material"), name);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(-200, -300, 200)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ }
+
+ if (name == QStringLiteral("materials/Copper")) {
+ data.insert(QStringLiteral("name"), QStringLiteral("Copper Sphere"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Sphere"));
+ data.insert(QStringLiteral("material"), name);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(-200, 300, 200)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ }
+
+ if (name == QStringLiteral("materials/Just Yellow")) {
+ QHash<QString, QVariant> data;
+ data.insert(QStringLiteral("name"), QStringLiteral("Yellow Cube"));
+ data.insert(QStringLiteral("sourcepath"), QStringLiteral("#Cube"));
+ data.insert(QStringLiteral("material"), name);
+ data.insert(QStringLiteral("position"),
+ QVariant::fromValue<QVector3D>(QVector3D(200, -300, 200)));
+ createElement(QStringLiteral("Scene.Layer"), QStringLiteral("Slide1"), data);
+ }
+ });
+
+ // Create material after start
+ QTimer::singleShot(1000, [&]() {
+ QString md = loadMatDefFile(QStringLiteral(
+ ":/scenes/simple_cube_animation/materials/Basic Blue.materialdef"));
+ // Modify the diffuse color and material name so that we can be sure it is a new one
+ md.replace(QStringLiteral("Basic Blue"), QStringLiteral("Just Yellow"));
+ md.replace(QRegularExpression(QStringLiteral("\"diffuse\">.*<")),
+ QStringLiteral("\"diffuse\">1 1 0 1<"));
+ m_presentation->createMaterial(QStringLiteral("Scene"), md);
+ });
+
+ QVERIFY(spyExited.wait(20000));
+ QCOMPARE(spyMatCreated.count(), 4);
+ QTest::qWait(200); // Extra wait to verify slide change visually
+}
+
+void tst_qt3dsviewer::deleteCreatedElements(int interval)
+{
+ QTimer deleteTimer;
+ deleteTimer.setInterval(interval);
+ int elemCounter = m_createdElements.size() - 1;
+ QObject::connect(&deleteTimer, &QTimer::timeout, [&]() {
+ // Delete all elements we created previously
if (elemCounter >= 0) {
- m_presentation->deleteElement(massModels[elemCounter]);
+ m_presentation->deleteElement(m_createdElements[elemCounter]);
--elemCounter;
} else {
- qDebug() << "Extra models deleted";
- createTimer.stop();
+ qDebug() << "Extra elements deleted";
+ deleteTimer.stop();
}
});
- qDebug() << "Start deleting extra models";
- createTimer.setInterval(1);
- createTimer.start();
+ qDebug() << "Start deleting extra elements";
+ deleteTimer.start();
- // Switch to slide 1
- QVERIFY(spyExited.wait(20000));
+ while (deleteTimer.isActive())
+ QTest::qWait(20);
+
+ m_createdElements.clear();
+}
+
+void tst_qt3dsviewer::createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties)
+{
+ m_createdElements << parentElementPath + QLatin1Char('.')
+ + properties[QStringLiteral("name")].toString();
+ m_presentation->createElement(parentElementPath, slideName, properties);
}
QTEST_MAIN(tst_qt3dsviewer)
diff --git a/tests/auto/viewer/tst_qt3dsviewer.h b/tests/auto/viewer/tst_qt3dsviewer.h
index f50bf935..bd5d0cd9 100644
--- a/tests/auto/viewer/tst_qt3dsviewer.h
+++ b/tests/auto/viewer/tst_qt3dsviewer.h
@@ -56,12 +56,19 @@ private Q_SLOTS:
void testFrameUpdates();
void testSettings();
void testCreateElement();
+ void testCreateMaterial();
private:
+ void deleteCreatedElements(int interval);
+ void createElement(const QString &parentElementPath, const QString &slideName,
+ const QHash<QString, QVariant> &properties);
+
QQuickView m_viewer;
QObject *m_studio3DItem = nullptr;
Q3DSPresentation *m_presentation = nullptr;
Q3DSViewerSettings *m_settings = nullptr;
+ QStringList m_createdElements;
+
};
#endif // TST_QT3DSVIEWER
diff --git a/tests/auto/viewer/tst_qt3dsviewer.qml b/tests/auto/viewer/tst_qt3dsviewer.qml
index 2368f039..e65a49db 100644
--- a/tests/auto/viewer/tst_qt3dsviewer.qml
+++ b/tests/auto/viewer/tst_qt3dsviewer.qml
@@ -55,7 +55,7 @@ Studio3D {
width: 800
height: 800
Presentation {
- source: "qrc:/../../scenes/simple_cube_animation/simple_cube_animation.uia"
+ source: "qrc:/scenes/simple_cube_animation/simple_cube_animation.uia"
}
ViewerSettings {
}
diff --git a/tests/auto/viewer/viewer.qrc b/tests/auto/viewer/viewer.qrc
index d85ee786..dcdddbea 100644
--- a/tests/auto/viewer/viewer.qrc
+++ b/tests/auto/viewer/viewer.qrc
@@ -4,6 +4,13 @@
<file>../../scenes/simple_cube_animation/presentations/simple_cube_animation.uip</file>
<file>../../scenes/simple_cube_animation/materials/Basic Green.materialdef</file>
<file>../../scenes/simple_cube_animation/materials/Basic Red.materialdef</file>
+ <file>../../scenes/simple_cube_animation/materials/Basic Blue.materialdef</file>
+ <file>../../scenes/simple_cube_animation/materials/Basic Texture.materialdef</file>
+ <file>../../scenes/simple_cube_animation/materials/Copper.materialdef</file>
+ <file>../../scenes/simple_cube_animation/materials/copper.shader</file>
+ <file>../../scenes/simple_cube_animation/maps/materials/shadow.png</file>
+ <file>../../scenes/simple_cube_animation/maps/materials/spherical_checker.png</file>
+ <file>../../scenes/simple_cube_animation/maps/QT-symbol.png</file>
<file>tst_qt3dsviewer.qml</file>
</qresource>
</RCC>
diff --git a/tests/scenes/simple_cube_animation/maps/QT-symbol.png b/tests/scenes/simple_cube_animation/maps/QT-symbol.png
new file mode 100644
index 00000000..752a2e2f
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/maps/QT-symbol.png
Binary files differ
diff --git a/tests/scenes/simple_cube_animation/maps/materials/shadow.png b/tests/scenes/simple_cube_animation/maps/materials/shadow.png
new file mode 100644
index 00000000..599b1ccc
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/maps/materials/shadow.png
Binary files differ
diff --git a/tests/scenes/simple_cube_animation/maps/materials/spherical_checker.png b/tests/scenes/simple_cube_animation/maps/materials/spherical_checker.png
new file mode 100644
index 00000000..e42394dd
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/maps/materials/spherical_checker.png
Binary files differ
diff --git a/tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef b/tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef
new file mode 100644
index 00000000..7fdda62b
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef
@@ -0,0 +1,25 @@
+<MaterialData version="1.0">
+ <Property name="shaderlighting">Pixel</Property>
+ <Property name="blendmode">Normal</Property>
+ <Property name="diffuse">0 0.482353 1 1</Property>
+ <Property name="specularamount">0</Property>
+ <Property name="specularroughness">0</Property>
+ <Property name="opacity">100</Property>
+ <Property name="emissivecolor">1 1 1 1</Property>
+ <Property name="emissivepower">0</Property>
+ <Property name="bumpamount">0.5</Property>
+ <Property name="displaceamount">20</Property>
+ <Property name="translucentfalloff">1</Property>
+ <Property name="diffuselightwrap">0</Property>
+ <Property name="specularmodel">Default</Property>
+ <Property name="speculartint">1 1 1 1</Property>
+ <Property name="ior">1.5</Property>
+ <Property name="fresnelPower">0</Property>
+ <Property name="vertexcolors">False</Property>
+ <Property name="sourcepath"></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Material</Property>
+ <Property name="name"><![CDATA[materials/Basic Blue]]></Property>
+ <Property name="path"><![CDATA[C:/dev/qt/NDD/qt3ds2/tests/scenes/simple_cube_animation/materials/Basic Blue.materialdef]]></Property>
+</MaterialData> \ No newline at end of file
diff --git a/tests/scenes/simple_cube_animation/materials/Basic Green.materialdef b/tests/scenes/simple_cube_animation/materials/Basic Green.materialdef
index 5dbd3d6a..59a0ae02 100644
--- a/tests/scenes/simple_cube_animation/materials/Basic Green.materialdef
+++ b/tests/scenes/simple_cube_animation/materials/Basic Green.materialdef
@@ -1,18 +1,18 @@
<MaterialData version="1.0">
<Property name="shaderlighting">Pixel</Property>
<Property name="blendmode">Normal</Property>
- <Property name="diffuse">0 1 0.0313726</Property>
+ <Property name="diffuse">0.180392 1 0 1</Property>
<Property name="specularamount">0</Property>
<Property name="specularroughness">0</Property>
<Property name="opacity">100</Property>
- <Property name="emissivecolor">1 1 1</Property>
+ <Property name="emissivecolor">1 1 1 1</Property>
<Property name="emissivepower">0</Property>
<Property name="bumpamount">0.5</Property>
<Property name="displaceamount">20</Property>
<Property name="translucentfalloff">1</Property>
<Property name="diffuselightwrap">0</Property>
<Property name="specularmodel">Default</Property>
- <Property name="speculartint">1 1 1</Property>
+ <Property name="speculartint">1 1 1 1</Property>
<Property name="ior">1.5</Property>
<Property name="fresnelPower">0</Property>
<Property name="vertexcolors">False</Property>
diff --git a/tests/scenes/simple_cube_animation/materials/Basic Red.materialdef b/tests/scenes/simple_cube_animation/materials/Basic Red.materialdef
index b5b43717..ecb9bb43 100644
--- a/tests/scenes/simple_cube_animation/materials/Basic Red.materialdef
+++ b/tests/scenes/simple_cube_animation/materials/Basic Red.materialdef
@@ -1,18 +1,18 @@
<MaterialData version="1.0">
<Property name="shaderlighting">Pixel</Property>
<Property name="blendmode">Normal</Property>
- <Property name="diffuse">1 0.0196078 0.0352941</Property>
+ <Property name="diffuse">1 0 0.0156863 1</Property>
<Property name="specularamount">0</Property>
<Property name="specularroughness">0</Property>
<Property name="opacity">100</Property>
- <Property name="emissivecolor">1 1 1</Property>
+ <Property name="emissivecolor">1 1 1 1</Property>
<Property name="emissivepower">0</Property>
<Property name="bumpamount">0.5</Property>
<Property name="displaceamount">20</Property>
<Property name="translucentfalloff">1</Property>
<Property name="diffuselightwrap">0</Property>
<Property name="specularmodel">Default</Property>
- <Property name="speculartint">1 1 1</Property>
+ <Property name="speculartint">1 1 1 1</Property>
<Property name="ior">1.5</Property>
<Property name="fresnelPower">0</Property>
<Property name="vertexcolors">False</Property>
diff --git a/tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef b/tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef
new file mode 100644
index 00000000..4defa98f
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef
@@ -0,0 +1,63 @@
+<MaterialData version="1.0">
+ <Property name="shaderlighting">Pixel</Property>
+ <Property name="blendmode">Normal</Property>
+ <Property name="diffuse">0.752941 0.756863 1 1</Property>
+ <Property name="diffusemap"><![CDATA[./maps/materials/spherical_checker.png]]></Property>
+ <Property name="diffusemap2"><![CDATA[./maps/QT-symbol.png]]></Property>
+ <Property name="specularamount">0</Property>
+ <Property name="specularroughness">0</Property>
+ <Property name="opacity">100</Property>
+ <Property name="emissivecolor">1 1 1 1</Property>
+ <Property name="emissivepower">0</Property>
+ <Property name="bumpamount">0.5</Property>
+ <Property name="displaceamount">20</Property>
+ <Property name="translucentfalloff">1</Property>
+ <Property name="diffuselightwrap">0</Property>
+ <Property name="specularmodel">Default</Property>
+ <Property name="speculartint">1 1 1 1</Property>
+ <Property name="ior">1.5</Property>
+ <Property name="fresnelPower">0</Property>
+ <Property name="vertexcolors">False</Property>
+ <Property name="sourcepath"></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Material</Property>
+ <Property name="name"><![CDATA[materials/Basic Texture]]></Property>
+ <Property name="path"><![CDATA[C:/dev/qt/NDD/qt3ds2/tests/scenes/simple_cube_animation/materials/Basic Texture.materialdef]]></Property>
+ <TextureData name="diffusemap">
+ <Property name="scaleu">1</Property>
+ <Property name="scalev">1</Property>
+ <Property name="mappingmode">UV Mapping</Property>
+ <Property name="tilingmodehorz">Tiled</Property>
+ <Property name="tilingmodevert">Tiled</Property>
+ <Property name="rotationuv">0</Property>
+ <Property name="positionu">0</Property>
+ <Property name="positionv">0</Property>
+ <Property name="pivotu">0</Property>
+ <Property name="pivotv">0</Property>
+ <Property name="subpresentation"></Property>
+ <Property name="sourcepath"><![CDATA[./maps/materials/spherical_checker.png]]></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Image</Property>
+ <Property name="name"><![CDATA[Image]]></Property>
+ </TextureData>
+ <TextureData name="diffusemap2">
+ <Property name="scaleu">2</Property>
+ <Property name="scalev">3</Property>
+ <Property name="mappingmode">UV Mapping</Property>
+ <Property name="tilingmodehorz">Tiled</Property>
+ <Property name="tilingmodevert">Tiled</Property>
+ <Property name="rotationuv">0</Property>
+ <Property name="positionu">0</Property>
+ <Property name="positionv">0</Property>
+ <Property name="pivotu">0</Property>
+ <Property name="pivotv">0</Property>
+ <Property name="subpresentation"></Property>
+ <Property name="sourcepath"><![CDATA[./maps/QT-symbol.png]]></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">Image</Property>
+ <Property name="name"><![CDATA[Image]]></Property>
+ </TextureData>
+</MaterialData> \ No newline at end of file
diff --git a/tests/scenes/simple_cube_animation/materials/Copper.materialdef b/tests/scenes/simple_cube_animation/materials/Copper.materialdef
new file mode 100644
index 00000000..76880986
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/Copper.materialdef
@@ -0,0 +1,14 @@
+<MaterialData version="1.0">
+ <Property name="uEnvironmentTexture" type="Texture"><![CDATA[./maps/materials/spherical_checker.png]]></Property>
+ <Property name="uEnvironmentMappingEnabled">True</Property>
+ <Property name="uBakedShadowTexture" type="Texture"><![CDATA[./maps/materials/shadow.png]]></Property>
+ <Property name="uShadowMappingEnabled">False</Property>
+ <Property name="roughness">0</Property>
+ <Property name="metal_color">0.807843 0.45098 0.211765 1</Property>
+ <Property name="sourcepath"><![CDATA[./materials/copper.shader]]></Property>
+ <Property name="importid"></Property>
+ <Property name="importfile"></Property>
+ <Property name="type">CustomMaterial</Property>
+ <Property name="name"><![CDATA[materials/Copper]]></Property>
+ <Property name="path"><![CDATA[C:/dev/qt/NDD/qt3ds2/tests/scenes/simple_cube_animation/materials/Copper.materialdef]]></Property>
+</MaterialData> \ No newline at end of file
diff --git a/tests/scenes/simple_cube_animation/materials/copper.shader b/tests/scenes/simple_cube_animation/materials/copper.shader
new file mode 100644
index 00000000..cf9e1ad4
--- /dev/null
+++ b/tests/scenes/simple_cube_animation/materials/copper.shader
@@ -0,0 +1,178 @@
+<Material name="copper" version="1.0">
+ <MetaData >
+ <Property formalName="Environment Map" name="uEnvironmentTexture" description="Environment texture for the material" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="environment" default="./maps/materials/spherical_checker.png" category="Material"/>
+ <Property formalName="Enable Environment" name="uEnvironmentMappingEnabled" description="Enable environment mapping" type="Boolean" default="True" category="Material"/>
+ <Property formalName="Baked Shadow Map" name="uBakedShadowTexture" description="Baked shadow texture for the material" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="shadow" default="./maps/materials/shadow.png" category="Material"/>
+ <Property formalName="Shadow Mapping" name="uShadowMappingEnabled" description="Enable shadow mapping" type="Boolean" default="False" category="Material"/>
+ <Property formalName="Roughness" name="roughness" type="Float" min="0.000000" max="1.000000" default="0.000000" description="Roughness of the material.\n0 = fully specular\n1 = fully diffuse" category="Material"/>
+ <Property formalName="Metal Color" name="metal_color" type="Color" default="0.805 0.395 0.305" description="Color of the material" category="Material"/>
+ </MetaData>
+ <Shaders type="GLSL" version="330">
+ <Shader>
+ <Shared> </Shared>
+<VertexShader>
+ </VertexShader>
+ <FragmentShader>
+
+// add enum defines
+#define scatter_reflect 0
+#define scatter_transmit 1
+#define scatter_reflect_transmit 2
+
+#define QT3DS_ENABLE_UV0 1
+#define QT3DS_ENABLE_WORLD_POSITION 1
+#define QT3DS_ENABLE_TEXTAN 1
+#define QT3DS_ENABLE_BINORMAL 0
+
+#include "vertexFragmentBase.glsllib"
+
+// set shader output
+out vec4 fragColor;
+
+// add structure defines
+struct layer_result
+{
+ vec4 base;
+ vec4 layer;
+ mat3 tanFrame;
+};
+
+
+// temporary declarations
+ vec4 tmpShadowTerm;
+
+layer_result layers[1];
+
+#include "SSAOCustomMaterial.glsllib"
+#include "sampleLight.glsllib"
+#include "sampleProbe.glsllib"
+#include "sampleArea.glsllib"
+#include "square.glsllib"
+#include "calculateRoughness.glsllib"
+#include "evalBakedShadowMap.glsllib"
+#include "evalEnvironmentMap.glsllib"
+#include "luminance.glsllib"
+#include "microfacetBSDF.glsllib"
+#include "physGlossyBSDF.glsllib"
+#include "simpleGlossyBSDF.glsllib"
+#include "fresnelLayer.glsllib"
+
+bool evalTwoSided()
+{
+ return( false );
+}
+
+vec3 computeFrontMaterialEmissive()
+{
+ return( vec3( 0, 0, 0 ) );
+}
+
+void computeFrontLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * microfacetBSDF( layers[0].tanFrame, lightDir, viewDir, lightSpecular, materialIOR, roughness, roughness, scatter_reflect );
+
+#endif
+}
+
+void computeFrontAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * lightSpecular * sampleAreaGlossy( layers[0].tanFrame, varWorldPos, lightIdx, viewDir, roughness, roughness );
+
+#endif
+}
+
+void computeFrontLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QT3DS_ENABLE_LIGHT_PROBE
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * microfacetSampledBSDF( layers[0].tanFrame, viewDir, roughness, roughness, scatter_reflect );
+
+#else
+ layers[0].base += tmpShadowTerm * vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += tmpShadowTerm * sampleGlossyAniso( layers[0].tanFrame, viewDir, roughness, roughness );
+
+#endif
+}
+
+vec3 computeBackMaterialEmissive()
+{
+ return( vec3(0, 0, 0) );
+}
+
+void computeBackLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular )
+{
+#if QT3DS_ENABLE_CG_LIGHTING
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+void computeBackLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor )
+{
+#if !QT3DS_ENABLE_LIGHT_PROBE
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#else
+ layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 );
+ layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 );
+#endif
+}
+
+float computeIOR()
+{
+ return( false ? 1.0 : luminance( vec3( 1, 1, 1 ) ) );
+}
+
+float evalCutout()
+{
+ return( 1.000000 );
+}
+
+vec3 computeNormal()
+{
+ return( normal );
+}
+
+void computeTemporaries()
+{
+ tmpShadowTerm = evalBakedShadowMap( texCoord0 );
+}
+
+vec4 computeLayerWeights( in float alpha )
+{
+ vec4 color;
+ color = fresnelLayer( normal, vec3( 25.65, 25.65, 25.65 ), 1.000000, metal_color.rgb, layers[0].layer, layers[0].base, alpha );
+ return color;
+}
+
+
+void initializeLayerVariables(void)
+{
+ // clear layers
+ layers[0].base = vec4(0.0, 0.0, 0.0, 1.0);
+ layers[0].layer = vec4(0.0, 0.0, 0.0, 1.0);
+ layers[0].tanFrame = orthoNormalize( mat3( tangent, cross(normal, tangent), normal ) );
+}
+
+ </FragmentShader>
+ </Shader>
+ </Shaders>
+<Passes >
+ <ShaderKey value="4"/>
+ <LayerKey count="1"/>
+ <Pass >
+ </Pass>
+</Passes>
+</Material>
diff --git a/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip b/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip
index 7cabcbf0..bfedf1e1 100644
--- a/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip
+++ b/tests/scenes/simple_cube_animation/presentations/simple_cube_animation.uip
@@ -9,32 +9,36 @@
<Layer id="Layer" variants="" >
<Camera id="Camera" />
<Light id="Light" />
- <Model id="Cube" >
+ <Model id="Cube" variants="" >
<ReferencedMaterial id="Basic Green" />
</Model>
- <Model id="Cube2" >
+ <Model id="Cube2" variants="" >
<ReferencedMaterial id="Basic Red" />
</Model>
</Layer>
<Material id="__Container" >
- <Material id="materials/Basic Green" />
<Material id="materials/Basic Red" />
+ <Material id="materials/Basic Green" />
</Material>
</Scene>
</Graph>
<Logic >
<State name="Master Slide" component="#Scene" >
- <Add ref="#Layer" background="SolidColor" backgroundcolor="0.584314 0.0941176 0.34902" />
+ <Add ref="#Layer" background="SolidColor" backgroundcolor="0.584314 0.0941176 0.34902 1" />
<Add ref="#Camera" />
- <Add ref="#Light" />
+ <Add ref="#Light" lighttype="Point" >
+ <AnimationTrack property="position.x" type="EaseInOut" >0 -341.785 100 100 5 269.972 100 100</AnimationTrack>
+ <AnimationTrack property="position.y" type="EaseInOut" >0 0 100 100 5 0 100 100</AnimationTrack>
+ <AnimationTrack property="position.z" type="EaseInOut" >0 0 100 100 5 0 100 100</AnimationTrack>
+ </Add>
<Add ref="#__Container" name="__Container" />
- <Add ref="#materials/Basic Green" name="materials/Basic Green" diffuse="0 1 0.0313726" importid="" />
- <Add ref="#materials/Basic Red" name="materials/Basic Red" diffuse="1 0.0196078 0.0352941" importid="" />
+ <Add ref="#materials/Basic Red" name="materials/Basic Red" diffuse="1 0 0.0156863 1" importid="" />
+ <Add ref="#materials/Basic Green" name="materials/Basic Green" diffuse="0.180392 1 0 1" importid="" />
<State id="Scene-Slide1" name="Slide1" playmode="Play Through To..." >
<Set ref="#Layer" endtime="5000" />
<Set ref="#Camera" endtime="5000" />
<Set ref="#Light" endtime="5000" />
- <Add ref="#Cube" name="Cube" endtime="5000" position="-408.071 -47.2654 600" sourcepath="#Cube" >
+ <Add ref="#Cube" name="Cube" endtime="5000" position="-458.877 -70.3589 600" sourcepath="#Cube" >
<AnimationTrack property="rotation.x" type="EaseInOut" >0 0 100 100 1 0 100 100 4 0 100 100 5 90 100 100 7 90 100 100 10 0 100 100</AnimationTrack>
<AnimationTrack property="rotation.y" type="EaseInOut" >0 0 100 100 1 0 100 100 4 90 100 100 5 0 100 100 7 0 100 100 10 0 100 100</AnimationTrack>
<AnimationTrack property="rotation.z" type="EaseInOut" >0 0 100 100 1 -90 100 100 4 -90 100 100 5 -90 100 100 7 0 100 100 10 0 100 100</AnimationTrack>