summaryrefslogtreecommitdiffstats
path: root/src/Runtime/Source/stateapplication/editor/Qt3DSSceneGraphArchitectDebugger.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/Source/stateapplication/editor/Qt3DSSceneGraphArchitectDebugger.cpp')
-rw-r--r--src/Runtime/Source/stateapplication/editor/Qt3DSSceneGraphArchitectDebugger.cpp574
1 files changed, 574 insertions, 0 deletions
diff --git a/src/Runtime/Source/stateapplication/editor/Qt3DSSceneGraphArchitectDebugger.cpp b/src/Runtime/Source/stateapplication/editor/Qt3DSSceneGraphArchitectDebugger.cpp
new file mode 100644
index 00000000..e15f587d
--- /dev/null
+++ b/src/Runtime/Source/stateapplication/editor/Qt3DSSceneGraphArchitectDebugger.cpp
@@ -0,0 +1,574 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#include "Qt3DSSceneGraphDebugger.h"
+#include "Qt3DSSceneGraphDebuggerValue.h"
+#include "Qt3DSSceneGraphDebuggerProtocol.h"
+#include "Qt3DSUIADatamodel.h"
+#include "Qt3DSStateEditorValue.h"
+#include "Qt3DSUIADatamodelValue.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "foundation/Qt3DSContainers.h"
+#include "Qt3DSKernelTypes.h"
+#include "Qt3DSHash.h" //we need to duplicate the hash attribute calls
+#include "EASTL/set.h"
+
+using namespace qt3ds;
+using namespace qt3ds::state;
+using namespace qt3ds::app;
+using namespace qt3ds::state::debugger;
+
+namespace {
+
+struct SAppElemVectorSet
+{
+ nvvector<SAppElement *> m_Elements;
+ eastl::hash_set<SAppElement *, eastl::hash<SAppElement *>, eastl::equal_to<SAppElement *>,
+ ForwardingAllocator>
+ m_Set;
+ SAppElemVectorSet(NVAllocatorCallback &alloc)
+ : m_Elements(alloc, "AppElemVectorSet")
+ , m_Set(ForwardingAllocator(alloc, "AppElemVectorSet"))
+ {
+ }
+
+ void insert(SAppElement *elem)
+ {
+ if (m_Set.insert(elem).second)
+ m_Elements.push_back(elem);
+ }
+
+ void clear()
+ {
+ m_Elements.clear();
+ m_Set.clear();
+ }
+ NVConstDataRef<SAppElement *> ToDataRef() { return m_Elements; }
+};
+
+struct SValueIndex
+{
+ QT3DSU32 m_ValueIndex;
+ QT3DSU32 m_Component;
+ SValueIndex(QT3DSU32 vi, QT3DSU32 component)
+ : m_ValueIndex(vi)
+ , m_Component(component)
+ {
+ }
+};
+
+struct SAppElementEntry
+{
+ Q3DStudio::TAttOrArgList m_AttList;
+ eastl::hash_map<QT3DSI32, SValueIndex> m_HashToIndexMap;
+ eastl::vector<app::SDatamodelValue> m_RuntimeValues;
+};
+
+struct SPresentationEntry
+{
+ CRegisteredString m_Id;
+ eastl::hash_map<CRegisteredString, SAppElement *> m_ElementMap;
+};
+
+Option<float> ValueToFloat(const SSGValue &val)
+{
+ if (val.getType() == SGPropertyValueTypes::Float)
+ return val.getData<float>();
+ return Empty();
+}
+
+Option<QT3DSI32> ValueToInteger(const SSGValue &val)
+{
+ if (val.getType() == SGPropertyValueTypes::I32)
+ return val.getData<QT3DSI32>();
+ return Empty();
+}
+
+Option<CRegisteredString> ValueToString(const SSGValue &val)
+{
+ if (val.getType() == SGPropertyValueTypes::String)
+ return val.getData<CRegisteredString>();
+ return Empty();
+}
+
+template <typename TDtype>
+struct SValueSetter
+{
+};
+
+template <>
+struct SValueSetter<float>
+{
+ static void SetValue(const SSGValue &incoming, float &outgoing, QT3DSU32 /*component*/)
+ {
+ Option<float> val = ValueToFloat(incoming);
+ if (val.hasValue())
+ outgoing = *val;
+ }
+};
+
+template <>
+struct SValueSetter<QT3DSVec2>
+{
+ static void SetValue(const SSGValue &incoming, QT3DSVec2 &outgoing, QT3DSU32 component)
+ {
+ Option<float> val = ValueToFloat(incoming);
+ if (val.hasValue()) {
+ switch (component) {
+ case 0:
+ outgoing.x = *val;
+ break;
+ case 1:
+ outgoing.y = *val;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+ }
+};
+
+template <>
+struct SValueSetter<QT3DSVec3>
+{
+ static void SetValue(const SSGValue &incoming, QT3DSVec3 &outgoing, QT3DSU32 component)
+ {
+ Option<float> val = ValueToFloat(incoming);
+ if (val.hasValue()) {
+ switch (component) {
+ case 0:
+ outgoing.x = *val;
+ break;
+ case 1:
+ outgoing.y = *val;
+ break;
+ case 2:
+ outgoing.z = *val;
+ break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+ }
+};
+
+template <>
+struct SValueSetter<QT3DSI32>
+{
+ static void SetValue(const SSGValue &incoming, QT3DSI32 &outgoing, QT3DSU32 /*component*/)
+ {
+ Option<QT3DSI32> val = ValueToInteger(incoming);
+ if (val.hasValue())
+ outgoing = *val;
+ }
+};
+
+template <>
+struct SValueSetter<eastl::string>
+{
+ static void SetValue(const SSGValue &incoming, eastl::string &outgoing, QT3DSU32 /*component*/)
+ {
+ Option<CRegisteredString> val = ValueToString(incoming);
+ if (val.hasValue())
+ outgoing = eastl::string(val->c_str());
+ }
+};
+
+template <>
+struct SValueSetter<bool>
+{
+ static void SetValue(const SSGValue &incoming, bool &outgoing, QT3DSU32 /*component*/)
+ {
+ Option<QT3DSI32> val = ValueToInteger(incoming);
+ if (val.hasValue())
+ outgoing = (*val) != 0 ? true : false;
+ }
+};
+
+// Element ref. Not sure what to do about this right now
+template <>
+struct SValueSetter<SGuid>
+{
+ static void SetValue(const SSGValue & /*incoming*/, SGuid & /*outgoing*/, QT3DSU32 /*component*/)
+ {
+ }
+};
+
+template <>
+struct SValueSetter<CRegisteredString>
+{
+ static void SetValue(const SSGValue & /*incoming*/, CRegisteredString & /*outgoing*/,
+ QT3DSU32 /*component*/)
+ {
+ QT3DS_ASSERT(false);
+ }
+};
+
+template <>
+struct SValueSetter<SObjectRef>
+{
+ static void SetValue(const SSGValue & /*incoming*/, SObjectRef & /*outgoing*/,
+ QT3DSU32 /*component*/)
+ {
+ }
+};
+
+template <>
+struct SValueSetter<CStringOrInt>
+{
+ static void SetValue(const SSGValue & /*incoming*/, CStringOrInt & /*outgoing*/,
+ QT3DSU32 /*component*/)
+ {
+ }
+};
+
+struct SValueSetterVisitor
+{
+ const SSGValue &m_Incoming;
+ QT3DSU32 m_Component;
+ SValueSetterVisitor &operator=(const SValueSetterVisitor &);
+ SValueSetterVisitor(const SSGValue &i, QT3DSU32 c)
+ : m_Incoming(i)
+ , m_Component(c)
+ {
+ }
+ template <typename TDataType>
+ void operator()(TDataType &dt)
+ {
+ SValueSetter<TDataType>::SetValue(m_Incoming, dt, m_Component);
+ }
+ // object refs can generate this response.
+ void operator()() {}
+};
+
+void SetComponentValue(const SSGValue &incoming, app::SDatamodelValue &outgoing, QT3DSU32 component)
+{
+ SValueSetterVisitor visitor(incoming, component);
+ outgoing.visit<void>(visitor);
+}
+
+struct SArchitectDebuggerImpl : public ISceneGraphArchitectDebugger
+{
+ NVFoundationBase &m_Foundation;
+ NVScopedRefCounted<IDatamodel> m_Datamodel;
+ NVScopedRefCounted<IDebugOutStream> m_Stream;
+ ISceneGraphArchitectDebuggerListener *m_Listener;
+ nvhash_map<QT3DSU64, SAppElement *> m_ElemAppElemMap;
+ nvhash_map<SAppElement *, SAppElementEntry> m_RuntimeValues;
+ SAppElemVectorSet m_DirtySet;
+ eastl::vector<SPresentationEntry> m_Presentations;
+ bool m_Valid;
+ QT3DSI32 mRefCount;
+
+ SArchitectDebuggerImpl(IDatamodel &dm)
+ : m_Foundation(dm.GetFoundation())
+ , m_Datamodel(dm)
+ , m_Stream(NULL)
+ , m_Listener(NULL)
+ , m_ElemAppElemMap(dm.GetFoundation().getAllocator(), "ElemAppMap")
+ , m_RuntimeValues(dm.GetFoundation().getAllocator(), "RuntimeValues")
+ , m_DirtySet(dm.GetFoundation().getAllocator())
+ , m_Valid(true)
+ , mRefCount(0)
+ {
+ }
+
+ void addRef() { atomicIncrement(&mRefCount); }
+ void release()
+ {
+ // ensure the datamodel sticks around until after we are destroyed
+ NVScopedRefCounted<IDatamodel> dm(m_Datamodel);
+ atomicDecrement(&mRefCount);
+ if (mRefCount <= 0) {
+ NVDelete(m_Foundation.getAllocator(), this);
+ }
+ }
+
+ virtual IDatamodel &GetDatamodel() { return *m_Datamodel; }
+
+ static QT3DSI32 GetHashValue(const char *name, const char *component, eastl::string &ioWorkspace)
+ {
+ ioWorkspace.assign(nonNull(name));
+ ioWorkspace.append(".");
+ ioWorkspace.append(component);
+ return Q3DStudio::CHash::HashAttribute(ioWorkspace.c_str());
+ }
+
+ void AppendAttribute(const char *name, const char *formalName, ERuntimeDataModelDataType dtype,
+ SAppElementEntry &theEntry)
+ {
+ SAttOrArg newValue;
+ newValue.m_Name = name;
+ newValue.m_FormalName = formalName;
+ newValue.m_DataType = dtype;
+ theEntry.m_AttList.push_back(newValue);
+ theEntry.m_RuntimeValues.push_back(qt3ds::app::SDatamodelValue());
+ }
+
+ void LoadAppElement(SAppElement &elem, SPresentationEntry &entry)
+ {
+ entry.m_ElementMap.insert(eastl::make_pair(
+ m_Datamodel->GetStringTable().RegisterStr(m_Datamodel->GetElementId(elem).c_str()),
+ &elem));
+ SAppElementEntry &theEntry = m_RuntimeValues[&elem];
+ theEntry.m_AttList = m_Datamodel->GetElementAttributes(elem);
+ theEntry.m_RuntimeValues = m_Datamodel->GetElementAttributeInitialValues(elem);
+ AppendAttribute("active", "Active", ERuntimeDataModelDataTypeBool, theEntry);
+
+ if (m_Datamodel->IsComponent(elem)) {
+ AppendAttribute("slide", "(Slide)", ERuntimeDataModelDataTypeLong, theEntry);
+ AppendAttribute("time", "(Time)", ERuntimeDataModelDataTypeLong, theEntry);
+ AppendAttribute("paused", "(Mode)", ERuntimeDataModelDataTypeBool, theEntry);
+ }
+ eastl::string hashTemp;
+ for (QT3DSU32 idx = 0, end = (QT3DSU32)theEntry.m_AttList.size(); idx < end; ++idx) {
+ // Build out the component hash names.
+ const Q3DStudio::SAttOrArg &theProp(theEntry.m_AttList[idx]);
+ switch (theProp.m_DataType) {
+ // one component, one hash, just hash the name
+ default:
+ theEntry.m_HashToIndexMap.insert(
+ eastl::make_pair((QT3DSI32)Q3DStudio::CHash::HashAttribute(theProp.m_Name.c_str()),
+ SValueIndex(idx, 0)));
+ break;
+ case ERuntimeDataModelDataTypeFloat2: {
+ theEntry.m_HashToIndexMap.insert(eastl::make_pair(
+ GetHashValue(theProp.m_Name.c_str(), "x", hashTemp), SValueIndex(idx, 0)));
+ theEntry.m_HashToIndexMap.insert(eastl::make_pair(
+ GetHashValue(theProp.m_Name.c_str(), "y", hashTemp), SValueIndex(idx, 1)));
+ } break;
+ case ERuntimeDataModelDataTypeFloat3: {
+ const char *compNames[3] = { "x", "y", "z" };
+ if (theProp.m_MetaType == ERuntimeAdditionalMetaDataTypeColor) {
+ compNames[0] = "r";
+ compNames[1] = "g";
+ compNames[2] = "b";
+ }
+
+ theEntry.m_HashToIndexMap.insert(
+ eastl::make_pair(GetHashValue(theProp.m_Name.c_str(), compNames[0], hashTemp),
+ SValueIndex(idx, 0)));
+ theEntry.m_HashToIndexMap.insert(
+ eastl::make_pair(GetHashValue(theProp.m_Name.c_str(), compNames[1], hashTemp),
+ SValueIndex(idx, 1)));
+ theEntry.m_HashToIndexMap.insert(
+ eastl::make_pair(GetHashValue(theProp.m_Name.c_str(), compNames[2], hashTemp),
+ SValueIndex(idx, 2)));
+ } break;
+ }
+ // Set a value
+ if (theEntry.m_RuntimeValues[idx].getType() == ERuntimeDataModelDataTypeNone) {
+ switch (theProp.m_DataType) {
+ case ERuntimeDataModelDataTypeFloat:
+ theEntry.m_RuntimeValues[idx] = 0.0f;
+ break;
+ case ERuntimeDataModelDataTypeFloat2:
+ theEntry.m_RuntimeValues[idx] = QT3DSVec2(0, 0);
+ break;
+ case ERuntimeDataModelDataTypeFloat3:
+ theEntry.m_RuntimeValues[idx] = QT3DSVec3(0, 0, 0);
+ break;
+ case ERuntimeDataModelDataTypeLong:
+ theEntry.m_RuntimeValues[idx] = (QT3DSI32)0;
+ break;
+ case ERuntimeDataModelDataTypeString:
+ theEntry.m_RuntimeValues[idx] = eastl::string();
+ break;
+ case ERuntimeDataModelDataTypeBool:
+ theEntry.m_RuntimeValues[idx] = false;
+ break;
+ case ERuntimeDataModelDataTypeStringRef:
+ theEntry.m_RuntimeValues[idx] = eastl::string();
+ break;
+ // object references are stored as string values.
+ case ERuntimeDataModelDataTypeObjectRef:
+ theEntry.m_RuntimeValues[idx] = eastl::string();
+ break;
+ case ERuntimeDataModelDataTypeStringOrInt:
+ theEntry.m_RuntimeValues[idx] = eastl::string();
+ break;
+ }
+ }
+ }
+ eastl::vector<SAppElement *> children = m_Datamodel->GetElementChildren(elem);
+ for (size_t childIdx = 0, childEnd = children.size(); childIdx < childEnd; ++childIdx) {
+ LoadAppElement(*children[childIdx], entry);
+ }
+ }
+
+ void LoadDatamodel()
+ {
+ eastl::vector<app::SPresentation> presentations = m_Datamodel->GetPresentations();
+ m_Presentations.clear();
+ m_RuntimeValues.clear();
+ m_ElemAppElemMap.clear();
+ m_Presentations.resize(presentations.size());
+ for (size_t idx = 0, end = presentations.size(); idx < end; ++idx) {
+ app::SPresentation &incoming(presentations[idx]);
+ SPresentationEntry &pres = m_Presentations[idx];
+ pres.m_Id = m_Datamodel->GetStringTable().RegisterStr(incoming.m_Id.c_str());
+ if (incoming.m_Scene)
+ LoadAppElement(*incoming.m_Scene, pres);
+ }
+ }
+
+ SAppElementEntry *GetRuntimeValues(app::SAppElement &elem)
+ {
+ nvhash_map<SAppElement *, SAppElementEntry>::iterator iter = m_RuntimeValues.find(&elem);
+ if (iter != m_RuntimeValues.end())
+ return &iter->second;
+ return NULL;
+ }
+
+ SPresentationEntry *FindPresentation(CRegisteredString &str)
+ {
+ for (size_t idx = 0, end = m_Presentations.size(); idx < end; ++idx)
+ if (m_Presentations[idx].m_Id == str)
+ return &m_Presentations[idx];
+ return NULL;
+ }
+
+ /*External interface for clients*/
+
+ void SetListener(ISceneGraphArchitectDebuggerListener *listener) { m_Listener = listener; }
+
+ Q3DStudio::TAttOrArgList GetElementAttributes(app::SAppElement &elem)
+ {
+ SAppElementEntry *entry = GetRuntimeValues(elem);
+ if (entry)
+ return entry->m_AttList;
+ return Q3DStudio::TAttOrArgList();
+ }
+
+ eastl::vector<app::SDatamodelValue> GetElementAttributeValues(app::SAppElement &elem)
+ {
+ SAppElementEntry *entry = GetRuntimeValues(elem);
+ if (entry)
+ return entry->m_RuntimeValues;
+ return eastl::vector<app::SDatamodelValue>();
+ }
+
+ void OnMessageReceived(const SDebugStreamMessage &inMessage)
+ {
+ if (!m_Valid)
+ return;
+ SSGProtocolReader theReader(inMessage.m_Data, m_Datamodel->GetStringTable());
+ while (theReader.Finished() == false && m_Valid) {
+ SSGProtocolMessageTypes::Enum theMessageType = theReader.MessageType();
+ switch (theMessageType) {
+ case SSGProtocolMessageTypes::Initialization: {
+ QT3DSU32 version = theReader.ReadInitialization();
+ if (version > GetSceneGraphProtocolVersion()) {
+ QT3DS_ASSERT(false);
+ m_Foundation.error(QT3DS_INVALID_OPERATION,
+ "Invalid scene graph debugger protocol version");
+ m_Valid = false;
+ }
+ } break;
+ case SSGProtocolMessageTypes::IdUpdate: {
+ SIdUpdate theUpdate = theReader.ReadIdUpdate();
+ SPresentationEntry *theEntry = FindPresentation(theUpdate.m_PresentationId);
+ if (theEntry) {
+ for (size_t idx = 0, end = theUpdate.m_IdUpdates.size(); idx < end; ++idx) {
+ const SElemMap &elemMap(theUpdate.m_IdUpdates[idx]);
+ eastl::hash_map<CRegisteredString, SAppElement *>::iterator iter =
+ theEntry->m_ElementMap.find(elemMap.m_Id);
+ if (iter != theEntry->m_ElementMap.end())
+ m_ElemAppElemMap[elemMap.m_Elem] = iter->second;
+ else {
+ QT3DS_ASSERT(false);
+ m_Foundation.error(QT3DS_WARN, "Failed to map element");
+ }
+ }
+ }
+ } break;
+ case SSGProtocolMessageTypes::ElemUpdate: {
+ SElemUpdate theUpdate = theReader.ReadElemUpdate();
+ nvhash_map<QT3DSU64, SAppElement *>::iterator ptrToElem =
+ m_ElemAppElemMap.find(theUpdate.m_Elem);
+ if (ptrToElem != m_ElemAppElemMap.end()) {
+ nvhash_map<SAppElement *, SAppElementEntry>::iterator elemToEntry =
+ m_RuntimeValues.find(ptrToElem->second);
+ if (elemToEntry != m_RuntimeValues.end()) {
+ SAppElementEntry &theEntry(elemToEntry->second);
+ m_DirtySet.insert(elemToEntry->first);
+ for (size_t idx = 0, end = theUpdate.m_Updates.size(); idx < end; ++idx) {
+ const SValueUpdate &theValue(theUpdate.m_Updates[idx]);
+ eastl::hash_map<QT3DSI32, SValueIndex>::iterator hashIndex =
+ theEntry.m_HashToIndexMap.find(theValue.m_Hash);
+ if (hashIndex != theEntry.m_HashToIndexMap.end()) {
+ const SValueIndex theIdx = hashIndex->second;
+ SetComponentValue(theValue.m_Value,
+ theEntry.m_RuntimeValues[theIdx.m_ValueIndex],
+ theIdx.m_Component);
+ }
+ }
+ } else {
+ QT3DS_ASSERT(false);
+ m_Foundation.error(QT3DS_WARN, "Failed to map element");
+ }
+ } else {
+ QT3DS_ASSERT(false);
+ m_Foundation.error(QT3DS_WARN, "Failed to map element");
+ }
+ } break;
+ case SSGProtocolMessageTypes::Frame: {
+ NVConstDataRef<SAppElement *> dirtyItems = m_DirtySet.ToDataRef();
+ if (dirtyItems.size() && m_Listener) {
+ m_Listener->OnItemsDirty(dirtyItems);
+ m_DirtySet.clear();
+ }
+ } break;
+ }
+ } // end while
+ }
+
+ void AttachToStream(IDebugOutStream &inStream) { m_Stream = &inStream; }
+
+ void RefreshData(bool inNeedReloadData)
+ {
+ if (inNeedReloadData)
+ m_Datamodel->RefreshFile();
+ LoadDatamodel();
+ }
+};
+}
+
+ISceneGraphArchitectDebugger &
+ISceneGraphArchitectDebugger::Create(qt3ds::app::IDatamodel &inDatamodel)
+{
+ SArchitectDebuggerImpl &retval =
+ *QT3DS_NEW(inDatamodel.GetFoundation().getAllocator(), SArchitectDebuggerImpl)(inDatamodel);
+ retval.LoadDatamodel();
+ return retval;
+}