summaryrefslogtreecommitdiffstats
path: root/src/Runtime/Source/runtime/Qt3DSApplication.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/Source/runtime/Qt3DSApplication.cpp')
-rw-r--r--src/Runtime/Source/runtime/Qt3DSApplication.cpp1831
1 files changed, 1831 insertions, 0 deletions
diff --git a/src/Runtime/Source/runtime/Qt3DSApplication.cpp b/src/Runtime/Source/runtime/Qt3DSApplication.cpp
new file mode 100644
index 00000000..249070c2
--- /dev/null
+++ b/src/Runtime/Source/runtime/Qt3DSApplication.cpp
@@ -0,0 +1,1831 @@
+/****************************************************************************
+**
+** 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$
+**
+****************************************************************************/
+
+// We need a Qt header first here because Qt's metatype system insists that Bool
+// can not be defined first before Qt headers are included and the includes below
+// define Bool by way of Xll/XLib.h via khronos -> egl -> X11
+#include <QImage>
+
+#include "RuntimePrefix.h"
+#include "Qt3DSApplication.h"
+#include "Qt3DSApplicationValues.h"
+#include "foundation/Qt3DSAtomic.h"
+#include "Qt3DSMemory.h"
+#include "Qt3DSRuntimeFactory.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/Qt3DSBroadcastingAllocator.h"
+#include "foundation/FileTools.h"
+#include "Qt3DSIScriptBridge.h"
+#include "foundation/Qt3DSOption.h"
+#include "foundation/XML.h"
+#include "foundation/IOStreams.h"
+#include "foundation/Qt3DSContainers.h"
+#include "EASTL/hash_map.h"
+#include "Qt3DSPresentation.h"
+#include "Qt3DSInputEventTypes.h"
+#include "Qt3DSSceneManager.h"
+#include "Qt3DSIScene.h"
+#include "Qt3DSInputEngine.h"
+#include "Qt3DSStateVisualBindingContext.h"
+#include "Qt3DSMetadata.h"
+#include "Qt3DSUIPParser.h"
+#include "foundation/Socket.h"
+#include "Qt3DSStateDebugStreams.h"
+#include "Qt3DSSceneGraphDebugger.h"
+#include "Qt3DSSceneGraphDebuggerValue.h"
+#include "EventPollingSystem.h"
+#include "Qt3DSRenderContextCore.h"
+#include "foundation/Qt3DSPerfTimer.h"
+#include "foundation/SerializationTypes.h"
+#include "EASTL/sort.h"
+#include "Qt3DSRenderBufferLoader.h"
+#include "foundation/Qt3DSMutex.h"
+#include "foundation/Qt3DSSync.h"
+#include "Qt3DSTextRenderer.h"
+#include "Qt3DSRenderThreadPool.h"
+#include "foundation/StringConversionImpl.h"
+#include "Qt3DSRenderLoadedTexture.h"
+#include "render/Qt3DSRenderContext.h"
+#include "Qt3DSActivationManager.h"
+#include "Qt3DSRenderer.h"
+#include "Qt3DSRenderShaderCache.h"
+#include "Qt3DSRenderInputStreamFactory.h"
+#include "Qt3DSAudioPlayer.h"
+#include "Qt3DSElementSystem.h"
+#include <QtCore/qlibraryinfo.h>
+#include <QtCore/qpair.h>
+#include <QtCore/qdir.h>
+#include "q3dsvariantconfig_p.h"
+
+using namespace qt3ds;
+using namespace qt3ds::runtime;
+using namespace Q3DStudio;
+using qt3ds::state::debugger::ISceneGraphRuntimeDebugger;
+using qt3ds::state::debugger::SSGPropertyChange;
+
+namespace qt3ds {
+namespace foundation {
+template <>
+struct StringConversion<QT3DSVec2>
+{
+ void StrTo(const char8_t *buffer, QT3DSVec2 &item)
+ {
+ char *endPtr = NULL;
+ item.x = (float)strtod(buffer, &endPtr);
+ if (endPtr)
+ item.y = (float)strtod(endPtr, NULL);
+ }
+};
+}
+}
+
+namespace {
+struct SDebugSettings
+{
+ eastl::string m_Server;
+ int m_Port;
+ bool m_Listen;
+ SDebugSettings()
+ : m_Port(0)
+ , m_Listen(false)
+ {
+ }
+};
+
+struct SFrameTimer
+{
+ int m_FrameCount;
+ QT3DSU64 m_FrameTime;
+ SFrameTimer(QT3DSU64 fc = 0)
+ : m_FrameCount(fc)
+ , m_FrameTime(qt3ds::foundation::Time::getCurrentCounterValue())
+ {
+ }
+
+ QT3DSF32 GetElapsedSeconds(QT3DSU64 currentTime) const
+ {
+ QT3DSU64 diff = currentTime - m_FrameTime;
+ QT3DSF32 diffNanos
+ = static_cast<QT3DSF32>(qt3ds::foundation::Time::sCounterFreq.toTensOfNanos(diff));
+ return diffNanos / qt3ds::foundation::Time::sNumTensOfNanoSecondsInASecond;
+ }
+
+ QT3DSF32 GetElapsedSeconds() const
+ {
+ return GetElapsedSeconds(qt3ds::foundation::Time::getCurrentCounterValue());
+ }
+
+ QPair<QT3DSF32, int> GetFPS(int updateFC)
+ {
+ int elapsedFrames = updateFC - m_FrameCount;
+ QT3DSU64 currentTime = qt3ds::foundation::Time::getCurrentCounterValue();
+ QT3DSF32 elapsedSeconds = GetElapsedSeconds(currentTime);
+ QT3DSF32 retval = elapsedFrames / elapsedSeconds;
+ m_FrameCount = updateFC;
+ m_FrameTime = currentTime;
+ return qMakePair(retval, elapsedFrames);
+ }
+};
+
+struct SRefCountedAssetValue : public SAssetValue
+{
+ NVFoundationBase &m_Foundation;
+ QT3DSI32 mRefCount;
+ SRefCountedAssetValue(NVFoundationBase &fnd)
+ : SAssetValue()
+ , m_Foundation(fnd)
+ , mRefCount(0)
+ {
+ }
+
+ SRefCountedAssetValue(NVFoundationBase &fnd, const SAssetValue &asset)
+ : SAssetValue(asset)
+ , m_Foundation(fnd)
+ , mRefCount(0)
+ {
+ }
+
+ SRefCountedAssetValue(NVFoundationBase &fnd, const SPresentationAsset &asset)
+ : SAssetValue(asset)
+ , m_Foundation(fnd)
+ , mRefCount(0)
+ {
+ }
+
+ SRefCountedAssetValue(NVFoundationBase &fnd, const SBehaviorAsset &asset)
+ : SAssetValue(asset)
+ , m_Foundation(fnd)
+ , mRefCount(0)
+ {
+ }
+
+ SRefCountedAssetValue(NVFoundationBase &fnd, const SRenderPluginAsset &asset)
+ : SAssetValue(asset)
+ , m_Foundation(fnd)
+ , mRefCount(0)
+ {
+ }
+
+ SRefCountedAssetValue(NVFoundationBase &fnd, const SSCXMLAsset &asset)
+ : SAssetValue(asset)
+ , m_Foundation(fnd)
+ , mRefCount(0)
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation.getAllocator())
+};
+
+typedef nvhash_map<CRegisteredString, NVScopedRefCounted<SRefCountedAssetValue>> TIdAssetMap;
+typedef nvhash_map<THashValue, CRegisteredString> THashStrMap;
+typedef nvvector<eastl::pair<CRegisteredString, NVScopedRefCounted<SRefCountedAssetValue>>>
+TIdAssetList;
+typedef eastl::pair<QT3DSU32, TElement *> THandleElementPair;
+typedef NVConstDataRef<THandleElementPair> THandleElementDataBuffer;
+typedef nvvector<THandleElementDataBuffer> THandleElementDataBufferList;
+typedef nvhash_map<QT3DSU32, TElement *> THandleElementMap;
+
+struct SHandleElementPairComparator
+{
+ bool operator()(const THandleElementPair &lhs, const THandleElementPair &rhs) const
+ {
+ return lhs.first < rhs.first;
+ }
+};
+
+struct SApp;
+
+class IAppLoadContext : public NVRefCounted
+{
+public:
+ virtual void EndLoad() = 0;
+ virtual bool OnGraphicsInitialized(IRuntimeFactory &inFactory) = 0;
+ virtual bool HasCompletedLoading() = 0;
+ static IAppLoadContext &CreateXMLLoadContext(
+ SApp &inApp, NVConstDataRef<qt3ds::state::SElementReference> inStateReferences,
+ const char8_t *inScaleMode);
+};
+
+inline float Clamp(float val, float inMin = 0.0f, float inMax = 1.0f)
+{
+ if (val < inMin)
+ return inMin;
+ if (val > inMax)
+ return inMax;
+ return val;
+}
+
+// A set of common settings that may come from the UIA or from the command line.
+// command line settings always override uia settings.
+struct SApplicationSettings
+{
+ Option<bool> m_LayerCacheEnabled;
+ Option<bool> m_LayerGpuProfilingEnabled;
+ Option<bool> m_ShaderCachePersistenceEnabled;
+
+ SApplicationSettings() {}
+
+ template <typename TDataType>
+ static Option<TDataType> Choose(const Option<TDataType> &inCommandLine,
+ const Option<TDataType> &inUIAFile)
+ {
+ if (inCommandLine.hasValue())
+ return inCommandLine;
+ return inUIAFile;
+ }
+
+ SApplicationSettings(const SApplicationSettings &inCommandLine,
+ const SApplicationSettings &inUIAFileSettings)
+ : m_LayerCacheEnabled(
+ Choose(inCommandLine.m_LayerCacheEnabled, inUIAFileSettings.m_LayerCacheEnabled))
+ , m_LayerGpuProfilingEnabled(Choose(inCommandLine.m_LayerGpuProfilingEnabled,
+ inUIAFileSettings.m_LayerGpuProfilingEnabled))
+ , m_ShaderCachePersistenceEnabled(Choose(inCommandLine.m_ShaderCachePersistenceEnabled,
+ inUIAFileSettings.m_ShaderCachePersistenceEnabled))
+ {
+ }
+
+ static const char8_t *LayerCacheName() { return "layer-caching"; }
+ static const char8_t *LayerGpuProfilerName() { return "layer-gpu-profiling"; }
+ static const char8_t *ShaderCacheName() { return "shader-cache-persistence"; }
+
+ void ParseBoolEnableDisableItem(const IDOMReader &inReader, const char8_t *itemName,
+ Option<bool> &itemValue)
+ {
+ const char8_t *inItem;
+ if (const_cast<IDOMReader &>(inReader).UnregisteredAtt(itemName, inItem)) {
+ if (AreEqualCaseless(inItem, "disabled"))
+ itemValue = false;
+ else
+ itemValue = true;
+ }
+ }
+
+ void ParseBoolEnableDisableItem(const eastl::vector<eastl::string> &inCommandLine,
+ const char8_t *itemName, Option<bool> &itemValue)
+ {
+ eastl::string temp;
+ temp.assign("-");
+ temp.append(itemName);
+ for (QT3DSU32 idx = 0, end = inCommandLine.size(); idx < end; ++idx) {
+ if (inCommandLine[idx].find(temp) == 0) {
+ if (inCommandLine[idx].length() == temp.size()) {
+ qCWarning(qt3ds::INVALID_OPERATION)
+ << "Unable to parse parameter %s. Please pass =enable|disable as "
+ << "part of the parameter. " << temp.c_str();
+ } else {
+ temp = inCommandLine[idx].substr(temp.size() + 1);
+ eastl::string::size_type start = temp.find_first_of("'\"");
+ if (start != eastl::string::npos)
+ temp.erase(0, start);
+
+ eastl::string::size_type end = temp.find_first_of("'\"");
+ if (end != eastl::string::npos)
+ temp.erase(end);
+ if (AreEqualCaseless(temp.c_str(), "disabled"))
+ itemValue = false;
+ else
+ itemValue = true;
+ qCInfo(qt3ds::INVALID_OPERATION)
+ << "Item " << itemName
+ << (itemValue ? " enabled" : " disabled");
+ }
+ }
+ }
+ }
+
+ template <typename TReaderType>
+ void ParseItems(const TReaderType &inReader)
+ {
+ ParseBoolEnableDisableItem(inReader, LayerCacheName(), m_LayerCacheEnabled);
+ ParseBoolEnableDisableItem(inReader, LayerGpuProfilerName(), m_LayerGpuProfilingEnabled);
+ ParseBoolEnableDisableItem(inReader, ShaderCacheName(), m_ShaderCachePersistenceEnabled);
+ }
+
+ void Parse(IDOMReader &inReader) { ParseItems(inReader); }
+
+ void Parse(const eastl::vector<eastl::string> &inCommandLine) { ParseItems(inCommandLine); }
+
+ struct SOptionSerializer
+ {
+ bool m_HasValue;
+ bool m_Value;
+ QT3DSU8 m_Padding[2];
+ SOptionSerializer(const Option<bool> &inValue = Empty())
+ : m_HasValue(inValue.hasValue())
+ , m_Value(inValue.hasValue() ? *inValue : false)
+ {
+ m_Padding[0] = 0;
+ m_Padding[1] = 0;
+ }
+
+ operator Option<bool>() const
+ {
+ if (m_HasValue)
+ return m_Value;
+ return Empty();
+ }
+ };
+
+ void Save(IOutStream &outStream) const
+ {
+ outStream.Write(SOptionSerializer(m_LayerCacheEnabled));
+ outStream.Write(SOptionSerializer(m_LayerGpuProfilingEnabled));
+ outStream.Write(SOptionSerializer(m_ShaderCachePersistenceEnabled));
+ }
+
+ void Load(IInStream &inStream)
+ {
+ SOptionSerializer s;
+ inStream.Read(s);
+ m_LayerCacheEnabled = s;
+ inStream.Read(s);
+ m_LayerGpuProfilingEnabled = s;
+ inStream.Read(s);
+ m_ShaderCachePersistenceEnabled = s;
+ }
+};
+
+struct SDummyAudioPlayer : public IAudioPlayer
+{
+ virtual ~SDummyAudioPlayer() {}
+ bool PlaySoundFile(const char *inFilePath) override
+ {
+ (void *)inFilePath;
+ qCWarning(qt3ds::TRACE_INFO)
+ << "Qt3DSTegraApplication: Unimplemented method IAudioPlayer::PlaySoundFile";
+ return false;
+ }
+} g_DummyAudioPlayer;
+
+struct SAudioPlayerWrapper : public IAudioPlayer
+{
+private:
+ IApplication *m_Application;
+ IAudioPlayer *m_RealPlayer;
+
+public:
+ SAudioPlayerWrapper()
+ : m_Application(0)
+ , m_RealPlayer(&g_DummyAudioPlayer)
+ {
+ }
+ virtual ~SAudioPlayerWrapper() {}
+
+ void SetApplication(IApplication &inApplication) { m_Application = &inApplication; }
+
+ void SetPlayer(IAudioPlayer *inPlayer)
+ {
+ if (inPlayer)
+ m_RealPlayer = inPlayer;
+ else
+ m_RealPlayer = &g_DummyAudioPlayer;
+ }
+
+ bool PlaySoundFile(const char *inFilePath) override
+ {
+ eastl::string theFilePath(nonNull(inFilePath));
+ if (m_RealPlayer != &g_DummyAudioPlayer) {
+ qt3ds::foundation::CFileTools::CombineBaseAndRelative(
+ m_Application->GetProjectDirectory().c_str(), inFilePath, theFilePath);
+ }
+ return m_RealPlayer->PlaySoundFile(theFilePath.c_str());
+ }
+};
+
+struct SApp : public IApplication
+{
+
+ NVScopedRefCounted<Q3DStudio::IRuntimeFactoryCore> m_CoreFactory;
+ NVScopedRefCounted<Q3DStudio::IRuntimeFactory> m_RuntimeFactory;
+
+ Q3DStudio::CInputEngine *m_InputEnginePtr;
+ CAppStr m_ApplicationDir;
+ CAppStr m_ProjectDir;
+ Option<SDebugSettings> m_DebugSettings;
+ CAppStr m_InitialPresentationId;
+ CAppStr m_DLLDirectory;
+ TIdAssetMap m_AssetMap;
+ // Keep the assets ordered. This enables the uia order to mean something.
+ TIdAssetList m_OrderedAssets;
+ SPickFrame m_PickFrame;
+ SPickFrame m_MousePickCache;
+ SPickFrame m_MouseOverCache;
+ THashStrMap m_HashStrMap;
+ CTimer m_Timer;
+ Q3DStudio::INT64 m_ManualTime;
+ SFrameTimer m_FrameTimer;
+ Q3DStudio::INT32 m_FrameCount;
+ // the name of the file without extension.
+ eastl::string m_Filename;
+ Q3DSVariantConfig m_variantConfig;
+
+ qt3ds::foundation::NVScopedReleasable<IRuntimeMetaData> m_MetaData;
+ nvvector<eastl::pair<SBehaviorAsset, bool>> m_Behaviors;
+ NVScopedRefCounted<SocketSystem> m_SocketSystem;
+ NVScopedRefCounted<SocketStream> m_ServerStream;
+ NVScopedRefCounted<qt3ds::state::debugger::IMultiProtocolSocket> m_ProtocolSocket;
+ NVScopedRefCounted<qt3ds::state::debugger::IDebugger> m_StateDebugger;
+ NVScopedRefCounted<ISceneGraphRuntimeDebugger> m_SceneGraphDebugger;
+ NVScopedRefCounted<IActivityZoneManager> m_ActivityZoneManager;
+ NVScopedRefCounted<IElementAllocator> m_ElementAllocator;
+ nvvector<SSGPropertyChange> m_ChangeBuffer;
+
+ // Handles are loaded sorted but only added to the handle map when needed.
+ nvvector<char8_t> m_LoadBuffer;
+ nvvector<CPresentation *> m_PresentationBuffer;
+ Mutex m_RunnableMutex;
+ nvvector<NVScopedRefCounted<IAppRunnable>> m_ThreadRunnables;
+ nvvector<NVScopedRefCounted<IAppRunnable>> m_MainThreadRunnables;
+ NVScopedRefCounted<IAppLoadContext> m_AppLoadContext;
+ bool m_HideFPS;
+ bool m_DisableState;
+ bool m_ProfileLogging;
+ bool m_LastRenderWasDirty;
+ QT3DSU64 m_LastFrameStartTime;
+ QT3DSU64 m_ThisFrameStartTime;
+ double m_MillisecondsSinceLastFrame;
+ // We get odd oscillations if we do are too quick to report that the frame wasn't dirty
+ // after input.
+ int m_DirtyCountdown;
+ SApplicationSettings m_UIAFileSettings;
+ eastl::pair<NVDataRef<Q3DStudio::TElement *>, size_t> m_ElementLoadResult;
+
+ SAudioPlayerWrapper m_AudioPlayer;
+
+ Qt3DSAssetVisitor *m_visitor;
+
+ bool m_createSuccessful;
+
+ DataInputMap m_dataInputs;
+
+ QT3DSI32 mRefCount;
+ SApp(Q3DStudio::IRuntimeFactoryCore &inFactory, const char8_t *inAppDir)
+ : m_CoreFactory(inFactory)
+ , m_InputEnginePtr(NULL)
+ , m_ApplicationDir(inFactory.GetFoundation().getAllocator())
+ , m_ProjectDir(inFactory.GetFoundation().getAllocator())
+ , m_InitialPresentationId(inFactory.GetFoundation().getAllocator())
+ , m_DLLDirectory(inFactory.GetFoundation().getAllocator())
+ , m_AssetMap(inFactory.GetFoundation().getAllocator(), "SApp::m_AssetMap")
+ , m_OrderedAssets(inFactory.GetFoundation().getAllocator(), "SApp::m_OrderedAssets")
+ , m_HashStrMap(inFactory.GetFoundation().getAllocator(), "SApp::m_HashStrMap")
+ , m_Timer(inFactory.GetTimeProvider())
+ , m_ManualTime(0)
+ , m_FrameCount(0)
+ , m_Behaviors(inFactory.GetFoundation().getAllocator(), "SApp::m_Behaviors")
+ , m_ActivityZoneManager(IActivityZoneManager::CreateActivityZoneManager(
+ inFactory.GetFoundation(), inFactory.GetStringTable()))
+ , m_ElementAllocator(IElementAllocator::CreateElementAllocator(inFactory.GetFoundation(),
+ inFactory.GetStringTable()))
+ , m_ChangeBuffer(inFactory.GetFoundation().getAllocator(), "SApp::m_ChangeBuffer")
+ , m_LoadBuffer(inFactory.GetFoundation().getAllocator(), "SApp::m_LoadBuffer")
+ , m_PresentationBuffer(inFactory.GetFoundation().getAllocator(),
+ "SApp::m_PresentationBuffer")
+ , m_RunnableMutex(inFactory.GetFoundation().getAllocator())
+ , m_ThreadRunnables(inFactory.GetFoundation().getAllocator(), "SApp::m_ThreadRunnables")
+ , m_MainThreadRunnables(inFactory.GetFoundation().getAllocator(),
+ "SApp::m_MainThreadRunnables")
+ , m_HideFPS(true)
+ , m_DisableState(false)
+ , m_ProfileLogging(false)
+ , m_LastRenderWasDirty(true)
+ , m_LastFrameStartTime(0)
+ , m_ThisFrameStartTime(0)
+ , m_MillisecondsSinceLastFrame(0)
+ , m_DirtyCountdown(5)
+ , m_createSuccessful(false)
+ , mRefCount(0)
+ , m_visitor(nullptr)
+ {
+ m_AudioPlayer.SetApplication(*this);
+ eastl::string tempStr(inAppDir);
+ CFileTools::NormalizePath(tempStr);
+ m_ApplicationDir.assign(tempStr.c_str());
+
+ Q3DStudio_memset(&m_PickFrame, 0, sizeof(SPickFrame));
+ Q3DStudio_memset(&m_MousePickCache, 0, sizeof(SPickFrame));
+ Q3DStudio_memset(&m_MouseOverCache, 0, sizeof(SPickFrame));
+
+ m_Timer.Start();
+
+ m_CoreFactory->SetApplicationCore(this);
+ m_CoreFactory->GetScriptEngineQml().SetApplicationCore(*this);
+
+ m_CoreFactory->AddSearchPath(tempStr.c_str());
+ }
+
+ ~SApp()
+ {
+ EndLoad();
+ {
+ Mutex::ScopedLock __locker(m_RunnableMutex);
+ m_ThreadRunnables.clear();
+ }
+ // Ensure we stop the timer.
+ HasCompletedLoading();
+ m_AppLoadContext = NULL;
+
+ for (QT3DSU32 idx = 0, end = m_OrderedAssets.size(); idx < end; ++idx) {
+ SAssetValue &theAsset = *m_OrderedAssets[idx].second;
+ if (theAsset.getType() == AssetValueTypes::Presentation) {
+ SPresentationAsset &thePresAsset = *theAsset.getDataPtr<SPresentationAsset>();
+ if (thePresAsset.m_Presentation) {
+ Q3DStudio_delete(thePresAsset.m_Presentation, CPresentation);
+ thePresAsset.m_Presentation = NULL;
+ }
+ }
+ }
+ }
+
+ void setAssetVisitor(qt3ds::Qt3DSAssetVisitor *v) override
+ {
+ m_visitor = v;
+ }
+
+ NVDataRef<CPresentation *> GetPresentations()
+ {
+ if (m_PresentationBuffer.empty()) {
+ for (QT3DSU32 idx = 0, end = m_OrderedAssets.size(); idx < end; ++idx) {
+ SAssetValue &theAsset = *m_OrderedAssets[idx].second;
+ if (theAsset.getType() == AssetValueTypes::Presentation) {
+ SPresentationAsset &thePresAsset = *theAsset.getDataPtr<SPresentationAsset>();
+ if (thePresAsset.m_Presentation)
+ m_PresentationBuffer.push_back(thePresAsset.m_Presentation);
+ }
+ }
+ }
+ return m_PresentationBuffer;
+ }
+
+ void addRef() override { atomicIncrement(&mRefCount); }
+
+ void release() override
+ {
+ atomicDecrement(&mRefCount);
+ if (mRefCount <= 0)
+ NVDelete(m_CoreFactory->GetFoundation().getAllocator(), this);
+ }
+
+ void QueueForMainThread(IAppRunnable &inRunnable) override
+ {
+ Mutex::ScopedLock __locker(m_RunnableMutex);
+ m_ThreadRunnables.push_back(inRunnable);
+ }
+
+ // Debugging is disabled by default.
+ void EnableDebugging(bool inListen, const char8_t *inServer = NULL, int inPort = 0) override
+ {
+ SDebugSettings theSettings;
+ theSettings.m_Server.assign(nonNull(inServer));
+ if (theSettings.m_Server.size() == 0)
+ theSettings.m_Server = "localhost";
+ theSettings.m_Port = inPort;
+ if (!inPort)
+ theSettings.m_Port = 8172;
+ theSettings.m_Listen = inListen;
+ m_DebugSettings = theSettings;
+ // Done at load time only.
+ }
+
+ // state machine is enabled by default
+ void DisableStateMachine() override { m_DisableState = true; }
+
+ virtual void EnableProfileLogging()
+ {
+ m_ProfileLogging = true;
+ if (m_RuntimeFactory)
+ m_RuntimeFactory->GetScriptEngineQml().EnableProfiling();
+ }
+
+ // Verbose logging is disabled by default.
+ virtual void SetVerboseLogging(bool inEnableVerboseLogging)
+ {
+
+ }
+
+ ////////////////////////////////////////////////////////////////////////////
+ // Update rhythm implementations
+ ////////////////////////////////////////////////////////////////////////////
+
+ void SetPickFrame(const SPickFrame &inPickFrame)
+ {
+ // The model has changed, fire enter and exit mouse events
+ if (inPickFrame.m_Model != m_PickFrame.m_Model) {
+ // For determining onGroupedMouseOver/Out:
+ // arg1 = the original onMouseOut model and arg2 = the original onMouseOver model
+ UVariant theMouseOutModel;
+ UVariant theMouseOverModel;
+ theMouseOutModel.m_VoidPointer = m_PickFrame.m_Model;
+ theMouseOverModel.m_VoidPointer = inPickFrame.m_Model;
+
+ // It seems like you would want to 'onMouseOut' before you 'onMouseOver' something new?
+ if (m_PickFrame.m_Model) {
+ m_PickFrame.m_Model->GetBelongedPresentation()->FireEvent(
+ ON_MOUSEOUT, m_PickFrame.m_Model, &theMouseOutModel, &theMouseOverModel,
+ ATTRIBUTETYPE_POINTER, ATTRIBUTETYPE_POINTER);
+ }
+ if (inPickFrame.m_Model) {
+ inPickFrame.m_Model->GetBelongedPresentation()->FireEvent(
+ ON_MOUSEOVER, inPickFrame.m_Model, &theMouseOutModel, &theMouseOverModel,
+ ATTRIBUTETYPE_POINTER, ATTRIBUTETYPE_POINTER);
+ m_MouseOverCache = inPickFrame;
+ }
+ }
+
+ const TEventCommandHash *theEventArray[] = { &ON_MOUSEDOWN, &ON_MOUSEUP,
+ &ON_MIDDLEMOUSEDOWN, &ON_MIDDLEMOUSEUP,
+ &ON_RIGHTMOUSEDOWN, &ON_RIGHTMOUSEUP };
+ const TEventCommandHash *theClickEventArray[] = { &ON_MOUSECLICK, &ON_MIDDLEMOUSECLICK,
+ &ON_RIGHTMOUSECLICK };
+
+ // Click events...
+ // NOTE: This is a fancy way to iterate programatically over all the handled mouse inputs
+ // handled (declared in AKPickFrame.h for now)
+ // we iterate to INPUTBUTTONCOUNT (see comment in AKPickFrame.h) * 2, because we handle
+ // mouse down and up
+ for (QT3DSI32 theMouseEvtIter = 0; theMouseEvtIter < MOUSEBUTTONCOUNT - 1;
+ theMouseEvtIter++) {
+ // we effectively iterate to MOUSEBUTTONCOUNT * 2 (see comment in AKPickFrame.h) to
+ // handle mouse down and up
+ QT3DSI32 theMouseDownFlag = 1 << (theMouseEvtIter * 2);
+ QT3DSI32 theMouseUpFlag = 1 << (theMouseEvtIter * 2 + 1);
+
+ // on*MouseDown
+ // if this frame, the mouse button is down, and last frame it wasn't (new down click)
+ if (inPickFrame.m_Model && inPickFrame.m_InputFrame.m_MouseFlags & theMouseDownFlag
+ && !(m_PickFrame.m_InputFrame.m_MouseFlags & theMouseDownFlag)) {
+ // fire the 'on*MouseDown' event - which is at the even indices since the down
+ // events for each button are before the up
+ inPickFrame.m_Model->GetBelongedPresentation()->FireEvent(
+ *theEventArray[theMouseEvtIter * 2], inPickFrame.m_Model);
+
+ // cache this as the last item we 'onMouseDown' on
+ m_MousePickCache = inPickFrame;
+ }
+
+ // on*MouseUp
+ // if we mouse up on anything, send the event
+ if (inPickFrame.m_InputFrame.m_MouseFlags & theMouseUpFlag) {
+ // fire the 'on*MouseUp' event - odd indices (1,3,5 etc)
+ if (m_MousePickCache.m_Model) {
+ m_MousePickCache.m_Model->GetBelongedPresentation()->FireEvent(
+ *theEventArray[theMouseEvtIter * 2 + 1], m_MousePickCache.m_Model);
+ }
+
+ // on*MouseClick
+ // if we had a up click on the same item we were mouse down on last frame ... we had
+ // a click
+ if (inPickFrame.m_Model && inPickFrame.m_Model == m_MousePickCache.m_Model) {
+ inPickFrame.m_Model->GetBelongedPresentation()->FireEvent(
+ *theClickEventArray[theMouseEvtIter], inPickFrame.m_Model);
+ }
+
+ // clear the stored 'last mouse down' since we just got a mouse up
+ Q3DStudio_memset(&m_MousePickCache, 0, sizeof(SPickFrame));
+ }
+
+ // on*MouseDblClick
+ }
+
+ if (m_MouseOverCache.m_Model) {
+
+ if (inPickFrame.m_InputFrame.m_MouseFlags & VSCROLLWHEEL) {
+ UVariant theScrollValue;
+ theScrollValue.m_INT32 = inPickFrame.m_InputFrame.m_ScrollValue;
+ m_MouseOverCache.m_Model->GetBelongedPresentation()->FireEvent(
+ ON_VERTICALSCROLLWHEEL, m_MouseOverCache.m_Model, &theScrollValue,
+ NULL, ATTRIBUTETYPE_INT32);
+ } else if (inPickFrame.m_InputFrame.m_MouseFlags & HSCROLLWHEEL) {
+ UVariant theScrollValue;
+ theScrollValue.m_INT32 = inPickFrame.m_InputFrame.m_ScrollValue;
+ m_MouseOverCache.m_Model->GetBelongedPresentation()->FireEvent(
+ ON_HORIZONTALSCROLLWHEEL, m_MouseOverCache.m_Model, &theScrollValue,
+ NULL, ATTRIBUTETYPE_INT32);
+ }
+ }
+
+ // Do this last
+ m_PickFrame = inPickFrame;
+ }
+
+ void ClearPresentationDirtyLists()
+ {
+ NVDataRef<CPresentation *> thePresentations(GetPresentations());
+ for (QT3DSU32 idx = 0, end = thePresentations.size(); idx < end; ++idx)
+ thePresentations[idx]->ClearDirtyList();
+ }
+
+ void UpdatePresentations()
+ {
+ SStackPerfTimer __updateTimer(m_RuntimeFactory->GetPerfTimer(), "UpdatePresentations");
+ // Transfer the input frame to the kernel for pick processing
+ // the scene manager now handles the picking on each of its scenes
+ SetPickFrame(m_RuntimeFactory->GetSceneManager().AdvancePickFrame(
+ m_InputEnginePtr->GetInputFrame()));
+ // clear up mouse flag for horizontal and vertical scroll
+ m_InputEnginePtr->GetInputFrame().m_MouseFlags &= !(HSCROLLWHEEL | VSCROLLWHEEL);
+
+ // Update all the presentations.
+ // Animations are advanced based on m_Timer by default, but this can be overridden via
+ // SetTimeMilliSecs().
+ Q3DStudio::INT64 globalTime(GetTimeMilliSecs());
+
+ NVDataRef<CPresentation *> thePresentations(GetPresentations());
+
+ {
+ SStackPerfTimer __updateTimer(m_RuntimeFactory->GetPerfTimer(),
+ "UpdatePresentations - pre update");
+ for (QT3DSU32 idx = 0, end = m_OrderedAssets.size(); idx < end; ++idx) {
+ if (m_OrderedAssets[idx].second->getType() == AssetValueTypes::Presentation) {
+ SPresentationAsset &theAsset(
+ *m_OrderedAssets[idx].second->getDataPtr<SPresentationAsset>());
+ CPresentation *thePresentation = theAsset.m_Presentation;
+ if (thePresentation && thePresentation->GetActive())
+ thePresentation->PreUpdate(globalTime);
+ }
+ }
+ }
+ {
+ SStackPerfTimer __updateTimer(m_RuntimeFactory->GetPerfTimer(),
+ "UpdatePresentations - begin update");
+ for (QT3DSU32 idx = 0, end = m_OrderedAssets.size(); idx < end; ++idx) {
+ if (m_OrderedAssets[idx].second->getType() == AssetValueTypes::Presentation) {
+ SPresentationAsset &theAsset(
+ *m_OrderedAssets[idx].second->getDataPtr<SPresentationAsset>());
+ CPresentation *thePresentation = theAsset.m_Presentation;
+ if (thePresentation && thePresentation->GetActive())
+ thePresentation->BeginUpdate();
+ }
+ }
+ }
+ {
+ SStackPerfTimer __updateTimer(m_RuntimeFactory->GetPerfTimer(),
+ "UpdatePresentations - end update");
+
+ for (QT3DSU32 idx = 0, end = m_OrderedAssets.size(); idx < end; ++idx) {
+ if (m_OrderedAssets[idx].second->getType() == AssetValueTypes::Presentation) {
+ SPresentationAsset &theAsset(
+ *m_OrderedAssets[idx].second->getDataPtr<SPresentationAsset>());
+ CPresentation *thePresentation = theAsset.m_Presentation;
+ // allow EndUpdate also for inactive presentations so that we can
+ // activate it
+ if (thePresentation)
+ thePresentation->EndUpdate();
+ }
+ }
+ }
+ {
+ SStackPerfTimer __updateTimer(m_RuntimeFactory->GetPerfTimer(),
+ "UpdatePresentations - postupdate");
+
+ for (QT3DSU32 idx = 0, end = m_OrderedAssets.size(); idx < end; ++idx) {
+ if (m_OrderedAssets[idx].second->getType() == AssetValueTypes::Presentation) {
+ SPresentationAsset &theAsset(
+ *m_OrderedAssets[idx].second->getDataPtr<SPresentationAsset>());
+ CPresentation *thePresentation = theAsset.m_Presentation;
+ // allow PostUpdate also for inactive presentations so that we can
+ // activate it
+ if (thePresentation)
+ thePresentation->PostUpdate(globalTime);
+ }
+ }
+ }
+
+ // Run the garbage collection
+ m_CoreFactory->GetScriptEngineQml().StepGC();
+ }
+
+ void UpdateScenes() { m_RuntimeFactory->GetSceneManager().Update(); }
+
+ void Render()
+ {
+ SStackPerfTimer __updateTimer(m_RuntimeFactory->GetPerfTimer(), "Render");
+ CPresentation *pres = GetPrimaryPresentation();
+ if (pres)
+ m_LastRenderWasDirty = m_RuntimeFactory->GetSceneManager().RenderPresentation(pres);
+ }
+
+ void ResetDirtyCounter() { m_DirtyCountdown = 5; }
+
+ // Update all the presentations and render them.
+ void UpdateAndRender() override
+ {
+ QT3DS_ASSERT(m_AppLoadContext.mPtr == NULL);
+ m_ThisFrameStartTime = qt3ds::foundation::Time::getCurrentCounterValue();
+ if (m_LastFrameStartTime) {
+ QT3DSU64 durationSinceLastFrame = m_ThisFrameStartTime - m_LastFrameStartTime;
+ m_MillisecondsSinceLastFrame =
+ qt3ds::foundation::Time::sCounterFreq.toTensOfNanos(durationSinceLastFrame)
+ * (1.0 / 100000.0);
+ } else {
+ m_MillisecondsSinceLastFrame = 0;
+ }
+
+ if (m_ProtocolSocket)
+ m_ProtocolSocket->MessagePump();
+ ++m_FrameCount;
+
+ // Update any state systems
+ if (!m_DisableState)
+ m_CoreFactory->GetVisualStateContext().Initialize();
+
+ // First off, update any application level behaviors.
+ IScriptBridge &theScriptEngine = m_CoreFactory->GetScriptEngineQml();
+ for (QT3DSU32 idx = 0, end = m_Behaviors.size(); idx < end; ++idx) {
+ eastl::pair<SBehaviorAsset, bool> &entry(m_Behaviors[idx]);
+ if (!entry.second) {
+ entry.second = true;
+ theScriptEngine.ExecuteApplicationScriptFunction(entry.first.m_Handle,
+ "onInitialize");
+ }
+ }
+
+ // TODO: Initialize presentations
+
+ // Start any state systems
+ if (!m_DisableState)
+ m_CoreFactory->GetVisualStateContext().Start();
+
+ for (QT3DSU32 idx = 0, end = m_Behaviors.size(); idx < end; ++idx) {
+ eastl::pair<SBehaviorAsset, bool> &entry(m_Behaviors[idx]);
+ theScriptEngine.ExecuteApplicationScriptFunction(entry.first.m_Handle, "onUpdate");
+ }
+
+ if (!m_DisableState)
+ m_CoreFactory->GetVisualStateContext().Update();
+
+ UpdatePresentations();
+
+ if (m_ProtocolSocket) {
+ m_ProtocolSocket->MessagePump();
+ if (m_ProtocolSocket->Connected() == false)
+ exit(0);
+ }
+
+ UpdateScenes();
+
+ Render();
+
+ GetSceneGraphDebugger();
+
+ if (m_SceneGraphDebugger->IsConnected()) {
+ NVDataRef<CPresentation *> thePresentations(GetPresentations());
+ size_t thePresentationCount = thePresentations.size();
+ for (QT3DSU32 thePresentationIndex = 0; thePresentationIndex < thePresentationCount;
+ thePresentationIndex++) {
+ CPresentation *thePresentation = thePresentations[thePresentationIndex];
+ Q3DStudio::TElementList &theDirtyList =
+ thePresentation->GetFrameData().GetDirtyList();
+ for (QT3DSU32 idx = 0, end = theDirtyList.GetCount(); idx < end; ++idx) {
+ Q3DStudio::TElement &theElement = *theDirtyList[idx];
+ // Set active
+ m_ChangeBuffer.push_back(SSGPropertyChange());
+ QT3DSI32 active = theElement.GetActive() ? 1 : 0;
+ m_ChangeBuffer.back().m_Hash = CHash::HashAttribute("active");
+ m_ChangeBuffer.back().m_Value = qt3ds::state::debugger::SSGValue(active);
+ for (long attIdx = 0, attEnd = theElement.GetAttributeCount(); attIdx < attEnd;
+ ++attIdx) {
+ Option<qt3ds::runtime::element::TPropertyDescAndValuePtr> theValue =
+ theElement.GetPropertyByIndex(attIdx);
+ m_ChangeBuffer.push_back(SSGPropertyChange());
+ SSGPropertyChange &theChange(m_ChangeBuffer.back());
+ theChange.m_Hash = theValue->first.GetNameHash();
+ Q3DStudio::EAttributeType theAttType = theValue->first.m_Type;
+ switch (theAttType) {
+ case ATTRIBUTETYPE_HASH:
+ case ATTRIBUTETYPE_BOOL:
+ case ATTRIBUTETYPE_INT32:
+ theChange.m_Value =
+ qt3ds::state::debugger::SSGValue(
+ (QT3DSI32)theValue->second->m_INT32);
+ break;
+ case ATTRIBUTETYPE_FLOAT:
+ theChange.m_Value =
+ qt3ds::state::debugger::SSGValue(theValue->second->m_FLOAT);
+ break;
+ case ATTRIBUTETYPE_STRING: {
+ CRegisteredString data = m_CoreFactory->GetStringTable().HandleToStr(
+ theValue->second->m_StringHandle);
+ theChange.m_Value = qt3ds::state::debugger::SSGValue(data);
+ } break;
+ case ATTRIBUTETYPE_POINTER: {
+ void *ptrVal = theValue->second->m_VoidPointer;
+ QT3DSU64 coercedVal = (QT3DSU64)ptrVal;
+ theChange.m_Value = qt3ds::state::debugger::SSGValue(coercedVal);
+ } break;
+ case ATTRIBUTETYPE_ELEMENTREF: {
+ void *ptrVal = GetElementByHandle(theValue->second->m_ElementHandle);
+ QT3DSU64 coercedVal = (QT3DSU64)ptrVal;
+ theChange.m_Value = qt3ds::state::debugger::SSGValue(coercedVal);
+ } break;
+ default:
+ QT3DS_ASSERT(false);
+ break;
+ }
+ }
+ // If this is a component element, we have a few more properties we need to
+ // grab.
+ if (theElement.IsComponent()) {
+ TComponent &theComponent = static_cast<TComponent &>(theElement);
+ QT3DSI32 slide = theComponent.GetCurrentSlide();
+ QT3DSI32 isPaused = theComponent.GetPaused() ? 1 : 0;
+ QT3DSI32 time
+ =(QT3DSI32)thePresentation->GetActivityZone()->GetItemComponentTime(
+ theComponent);
+ m_ChangeBuffer.push_back(
+ SSGPropertyChange(CHash::HashAttribute("slide"), slide));
+ m_ChangeBuffer.push_back(
+ SSGPropertyChange(CHash::HashAttribute("paused"), isPaused));
+ m_ChangeBuffer.push_back(
+ SSGPropertyChange(CHash::HashAttribute("time"), time));
+ }
+ if (m_ChangeBuffer.size()) {
+ m_SceneGraphDebugger->OnPropertyChanged(&theElement, m_ChangeBuffer);
+ m_ChangeBuffer.clear();
+ }
+ }
+ }
+ m_SceneGraphDebugger->EndFrame();
+ }
+
+ m_InputEnginePtr->ClearInputFrame();
+ ClearPresentationDirtyLists();
+
+ if (m_ProtocolSocket)
+ m_ProtocolSocket->MessagePump();
+
+ if (!m_CoreFactory->GetEventSystem().GetAndClearEventFetchedFlag())
+ m_CoreFactory->GetEventSystem().PurgeEvents(); // GetNextEvents of event system has not
+ // been called in this round, so clear
+ // events to avoid events to be piled up
+
+ QT3DSU64 updateEndTime = qt3ds::foundation::Time::getCurrentCounterValue();
+ QT3DSU64 updateDuration = updateEndTime - m_ThisFrameStartTime;
+ double millis
+ = qt3ds::foundation::Time::sCounterFreq.toTensOfNanos(updateDuration)
+ * (1.0 / 100000);
+ if (floor(m_FrameTimer.GetElapsedSeconds()) > 0.0f) {
+ QPair<QT3DSF32, int> fps = m_FrameTimer.GetFPS(m_FrameCount);
+ m_RuntimeFactory->GetQt3DSRenderContext().SetFPS(fps);
+ if (m_ProfileLogging || !m_HideFPS) {
+ qCInfo(PERF_INFO, "Render Statistics: %3.2ffps, frame count %d",
+ fps.first, fps.second);
+ }
+ }
+
+ (void)millis;
+
+ /*if ( millis > 30.0 )
+ {
+ m_CoreFactory->GetFoundation().error( NVErrorCode::eDEBUG_INFO, __FILE__, __LINE__,
+ "Qt3DS Long Frame: %3.2fms", millis );
+ //Useful for figuring out where the frame time comes from.
+ m_CoreFactory->GetPerfTimer().OutputTimerData();
+
+ }
+ else*/
+ m_CoreFactory->GetPerfTimer().ResetTimerData();
+
+ fflush(stdout);
+ m_LastFrameStartTime = m_ThisFrameStartTime;
+ if (m_LastRenderWasDirty)
+ ResetDirtyCounter();
+ else
+ m_DirtyCountdown = NVMax(0, m_DirtyCountdown - 1);
+ }
+
+ // hook this up to -layer-caching.
+ // otherwise it might be hard to measure performance
+ bool IsApplicationDirty() override
+ {
+ return (m_DirtyCountdown > 0);
+ }
+
+ double GetMillisecondsSinceLastFrame() override { return m_MillisecondsSinceLastFrame; }
+
+ void MarkApplicationDirty() override { ResetDirtyCounter(); }
+
+ Q3DStudio::IAudioPlayer &GetAudioPlayer() override { return m_AudioPlayer; }
+ ////////////////////////////////////////////////////////////////////////////////
+ // Generalized save/load
+ ////////////////////////////////////////////////////////////////////////////////
+
+ bool LoadUIP(SPresentationAsset &inAsset,
+ NVConstDataRef<SElementAttributeReference> inExternalReferences)
+ {
+ GetMetaData();
+ eastl::string theFile;
+ CFileTools::CombineBaseAndRelative(GetProjectDirectory().c_str(), inAsset.m_Src.c_str(),
+ theFile);
+ // Check if the file event exists
+ eastl::string fullPath;
+ NVScopedRefCounted<qt3ds::render::IRefCountedInputStream> theStream
+ = m_CoreFactory->GetRenderContextCore().GetInputStreamFactory().GetStreamForFile(
+ theFile.c_str());
+ if (theStream) {
+ theStream = NULL;
+ CPresentation *thePresentation
+ = Q3DStudio_new(CPresentation) CPresentation(inAsset.m_Id.c_str(), this);
+ inAsset.m_Presentation = thePresentation;
+ thePresentation->SetFilePath(theFile.c_str());
+ NVScopedReleasable<IUIPParser> theUIPParser(IUIPParser::Create(
+ theFile.c_str(), *m_MetaData,
+ m_CoreFactory->GetInputStreamFactory(),
+ m_CoreFactory->GetStringTable()));
+ Q3DStudio::IScene *newScene = NULL;
+ ISceneGraphRuntimeDebugger &theDebugger = GetSceneGraphDebugger();
+ m_PresentationBuffer.clear();
+ // Map presentation id has to be called before load so that when we send the element
+ // id updates the system can also send the presentationid->id mapping.
+ theDebugger.MapPresentationId(thePresentation, inAsset.m_Id.c_str());
+ if (theUIPParser->Load(*thePresentation, inExternalReferences,
+ GetSceneGraphDebugger())) {
+ // Load the scene graph portion of the scene.
+ newScene = m_RuntimeFactory->GetSceneManager().LoadScene(
+ thePresentation, theUIPParser.mPtr,
+ m_CoreFactory->GetScriptEngineQml(),
+ m_variantConfig);
+ }
+
+ if (newScene == NULL) {
+ Q3DStudio_delete(thePresentation, CPresentation);
+ qCWarning(qt3ds::INVALID_OPERATION)
+ << "Unable to load presentation " << theFile.c_str();
+ inAsset.m_Presentation = NULL;
+ return false;
+ } else {
+ if (inAsset.m_Id.IsValid() && m_InitialPresentationId.empty())
+ m_InitialPresentationId.assign(inAsset.m_Id);
+
+ if (inAsset.m_Id.IsValid())
+ newScene->RegisterOffscreenRenderer(inAsset.m_Id);
+ return true;
+ }
+ }
+ qCWarning(qt3ds::INVALID_OPERATION) << "Unable to load presentation " << theFile.c_str();
+ return false;
+ }
+
+ bool LoadUIA(IDOMReader &inReader, NVFoundationBase &fnd)
+ {
+ NVConstDataRef<qt3ds::state::SElementReference> theStateReferences;
+ {
+ IDOMReader::Scope __preparseScope(inReader);
+ theStateReferences = m_CoreFactory->GetVisualStateContext().PreParseDocument(inReader);
+ }
+ {
+ m_UIAFileSettings.Parse(inReader);
+ }
+ {
+ IDOMReader::Scope __assetsScope(inReader);
+ if (!inReader.MoveToFirstChild("assets")) {
+ qCCritical(INVALID_OPERATION,
+ "UIA input xml doesn't contain <assets> tag; load failed");
+ return false;
+ }
+
+ eastl::string pathString;
+
+ const char8_t *initialItem = "";
+ inReader.UnregisteredAtt("initial", initialItem);
+ m_InitialPresentationId.clear();
+ if (!isTrivial(initialItem)) {
+ if (initialItem[0] == '#')
+ ++initialItem;
+
+ m_InitialPresentationId.assign(initialItem);
+ }
+ eastl::vector<SElementAttributeReference> theUIPReferences;
+ eastl::string tempString;
+
+ for (bool success = inReader.MoveToFirstChild(); success;
+ success = inReader.MoveToNextSibling()) {
+ IDOMReader::Scope __assetScope(inReader);
+ const char8_t *itemId("");
+ inReader.UnregisteredAtt("id", itemId);
+ const char8_t *src = "";
+ inReader.UnregisteredAtt("src", src);
+ pathString.clear();
+ if (!isTrivial(src))
+ CFileTools::CombineBaseAndRelative(m_ProjectDir.c_str(), src, pathString);
+
+ const char8_t *assetName = inReader.GetElementName();
+ if (AreEqual(assetName, "presentation")) {
+ SPresentationAsset theAsset(RegisterStr(itemId), RegisterStr(src));
+ bool activeFlag;
+ if (inReader.Att("active", activeFlag))
+ theAsset.m_Active = activeFlag;
+ RegisterAsset(theAsset);
+ } else if (AreEqual(assetName, "dataInput")) {
+ DataInputDef diDef;
+ const char8_t *name = "";
+ const char8_t *type = "";
+ const char8_t *evaluator = "";
+ diDef.value = QVariant::Invalid;
+ inReader.UnregisteredAtt("name", name);
+ inReader.UnregisteredAtt("type", type);
+ inReader.Att("min", diDef.min);
+ inReader.Att("max", diDef.max);
+ inReader.UnregisteredAtt("evaluator", evaluator);
+ if (AreEqual(type, "Ranged Number"))
+ diDef.type = DataInputTypeRangedNumber;
+ else if (AreEqual(type, "String"))
+ diDef.type = DataInputTypeString;
+ else if (AreEqual(type, "Float"))
+ diDef.type = DataInputTypeFloat;
+ else if (AreEqual(type, "Vector3"))
+ diDef.type = DataInputTypeVector3;
+ else if (AreEqual(type, "Vector2"))
+ diDef.type = DataInputTypeVector2;
+ else if (AreEqual(type, "Boolean"))
+ diDef.type = DataInputTypeBoolean;
+ else if (AreEqual(type, "Variant"))
+ diDef.type = DataInputTypeVariant;
+
+ if (AreEqual(type, "Evaluator")) {
+ diDef.type = DataInputTypeEvaluator;
+ diDef.evaluator = QString::fromUtf8(evaluator);
+ }
+
+ m_dataInputs.insert(QString::fromUtf8(name), diDef);
+ } else if (AreEqual(assetName, "renderplugin")) {
+ const char8_t *pluginArgs = "";
+ inReader.UnregisteredAtt("args", pluginArgs);
+ RegisterAsset(SRenderPluginAsset(RegisterStr(itemId), RegisterStr(src),
+ RegisterStr(pluginArgs)));
+ } else if (AreEqual(assetName, "statemachine")) {
+ const char8_t *dm = "";
+ inReader.UnregisteredAtt("datamodel", dm);
+ m_CoreFactory->GetVisualStateContext().LoadStateMachine(itemId, src,
+ nonNull(dm));
+ RegisterAsset(
+ SSCXMLAsset(RegisterStr(itemId), RegisterStr(src), RegisterStr(dm)));
+
+ } else if (AreEqual(assetName, "behavior")) {
+ SBehaviorAsset theAsset(RegisterStr(itemId), RegisterStr(src), 0);
+ RegisterAsset(theAsset);
+ } else if (AreEqual(assetName, "presentation-qml")) {
+ const char8_t *args = "";
+ inReader.UnregisteredAtt("args", args);
+ RegisterAsset(SQmlPresentationAsset(RegisterStr(itemId), RegisterStr(src),
+ RegisterStr(args)));
+ } else {
+ qCWarning(WARNING, "Unrecognized <assets> child %s", assetName);
+ }
+ }
+ } // end assets scope
+ const char8_t *initialScaleMode = "";
+ inReader.UnregisteredAtt("scalemode", initialScaleMode);
+
+ {
+ IDOMReader::Scope __machineScope(inReader);
+ m_CoreFactory->GetVisualStateContext().LoadVisualStateMapping(inReader);
+ }
+ m_AppLoadContext
+ = IAppLoadContext::CreateXMLLoadContext(*this, theStateReferences,
+ initialScaleMode);
+ return true;
+ }
+
+ DataInputMap &dataInputMap() override
+ {
+ return m_dataInputs;
+ }
+
+ struct SAppXMLErrorHandler : public qt3ds::foundation::CXmlErrorHandler
+ {
+ NVFoundationBase &m_Foundation;
+ const char8_t *m_FilePath;
+ SAppXMLErrorHandler(NVFoundationBase &fnd, const char8_t *filePath)
+ : m_Foundation(fnd)
+ , m_FilePath(filePath)
+ {
+ }
+
+ void OnXmlError(TXMLCharPtr errorName, int line, int /*column*/) override
+ {
+ qCWarning(INVALID_OPERATION, m_FilePath, line, "%s", errorName);
+ }
+ };
+
+ void ConnectDebugger()
+ {
+ NVFoundationBase &fnd(m_CoreFactory->GetFoundation());
+ Q3DStudio::IScriptBridge &theBridge = m_CoreFactory->GetScriptEngineQml();
+ if (m_DebugSettings.hasValue()) {
+ m_SocketSystem = SocketSystem::createSocketSystem(fnd);
+ if (m_DebugSettings->m_Listen) {
+ // Wait for connection request from debug server
+ qCInfo(TRACE_INFO, "Listening for debug connection on port %d",
+ m_DebugSettings->m_Port);
+ NVScopedRefCounted<SocketServer> theServer
+ = m_SocketSystem->createServer(m_DebugSettings->m_Port);
+ theServer->setTimeout(1000);
+ m_ServerStream = theServer->nextClient();
+ } else {
+ // Attempt to connect to the debug server
+ qCInfo(TRACE_INFO, "Attempt to connect to debug server %s:%d",
+ m_DebugSettings->m_Server.c_str(), m_DebugSettings->m_Port);
+ m_ServerStream = m_SocketSystem->createStream(m_DebugSettings->m_Server.c_str(),
+ m_DebugSettings->m_Port, 1000);
+ }
+ if (m_ServerStream) {
+ m_ServerStream->setTimeout(QT3DS_MAX_U32);
+ // This system declares protocols, we don't listen for new ones.
+ m_ProtocolSocket = qt3ds::state::debugger::IMultiProtocolSocket::CreateProtocolSocket(
+ fnd, *m_ServerStream, m_CoreFactory->GetStringTable(), NULL);
+ if (!m_ProtocolSocket->Initialize()) {
+ m_ProtocolSocket = NULL;
+ m_ServerStream = NULL;
+ m_SocketSystem = NULL;
+ qCWarning(WARNING,
+ "Initialization failed after connection to server, debug server %s:%d",
+ m_DebugSettings->m_Server.c_str(), m_DebugSettings->m_Port);
+
+ } else {
+ using namespace qt3ds::state::debugger;
+ theBridge.EnableDebugging(*m_ProtocolSocket);
+ NVScopedRefCounted<IMultiProtocolSocketStream> socketStream
+ = m_ProtocolSocket->CreateProtocol(
+ CProtocolNames::getSCXMLProtocolName(), NULL);
+ GetStateDebugger().OnServerConnected(*socketStream);
+
+ NVScopedRefCounted<IMultiProtocolSocketStream> theSGStream
+ = m_ProtocolSocket->CreateProtocol(
+ ISceneGraphRuntimeDebugger::GetProtocolName(), NULL);
+ GetSceneGraphDebugger().OnConnection(*theSGStream);
+ theSGStream->SetListener(&GetSceneGraphDebugger());
+ }
+ } else {
+ qCWarning(WARNING, "Failed to connect to debug server %s:%d",
+ m_DebugSettings->m_Server.c_str(), m_DebugSettings->m_Port);
+ }
+ }
+ }
+
+ virtual bool BeginLoad(const QString &sourcePath, const QStringList &variantList) override
+ {
+ SStackPerfTimer __loadTimer(m_CoreFactory->GetPerfTimer(), "Application: Begin Load");
+ eastl::string directory;
+ eastl::string filename;
+ eastl::string extension;
+ CFileTools::Split(sourcePath.toUtf8().constData(), directory, filename, extension);
+ eastl::string projectDirectory(directory);
+
+ m_ProjectDir.assign(projectDirectory.c_str());
+ m_CoreFactory->AddSearchPath(projectDirectory.c_str());
+
+ // add additional search path
+ QString projectDir = CFileTools::NormalizePathForQtUsage(projectDirectory.c_str());
+ if (!projectDir.startsWith(QStringLiteral(":"))) {
+ eastl::string relativeProjectDir;
+ CFileTools::CombineBaseAndRelative(m_ApplicationDir.c_str(), projectDirectory.c_str(),
+ relativeProjectDir);
+ m_CoreFactory->AddSearchPath(relativeProjectDir.c_str());
+ }
+
+ NVFoundationBase &fnd(m_CoreFactory->GetFoundation());
+
+ if (m_CoreFactory->GetRenderContextCore().GetTextRendererCore()) {
+ m_CoreFactory->GetRenderContextCore().GetTextRendererCore()->AddProjectFontDirectory(
+ projectDirectory.c_str());
+ m_CoreFactory->GetRenderContextCore().GetTextRendererCore()->BeginPreloadFonts(
+ m_CoreFactory->GetRenderContextCore().GetThreadPool(),
+ m_CoreFactory->GetRenderContextCore().GetPerfTimer());
+ }
+ m_Filename = filename;
+ m_variantConfig.setVariantList(variantList);
+ bool retval = false;
+ if (extension.comparei("uip") == 0) {
+#if !defined(_LINUXPLATFORM) && !defined(_INTEGRITYPLATFORM)
+ ConnectDebugger();
+#endif
+ m_InitialPresentationId.assign(filename.c_str());
+ eastl::string relativePath = "./";
+ relativePath.append(filename);
+ relativePath.append(".");
+ relativePath.append("uip");
+ RegisterAsset(SPresentationAsset(RegisterStr(filename.c_str()),
+ RegisterStr(relativePath.c_str())));
+ m_AppLoadContext = IAppLoadContext::CreateXMLLoadContext(
+ *this, NVDataRef<qt3ds::state::SElementReference>(), "");
+
+ retval = true;
+ } else if (extension.comparei("uia") == 0) {
+#if !defined(_LINUXPLATFORM) && !defined(_INTEGRITYPLATFORM)
+ ConnectDebugger();
+#endif
+ CFileSeekableIOStream inputStream(sourcePath, FileReadFlags());
+ if (inputStream.IsOpen()) {
+ NVScopedRefCounted<IStringTable> strTable(
+ IStringTable::CreateStringTable(fnd.getAllocator()));
+ NVScopedRefCounted<IDOMFactory> domFactory(
+ IDOMFactory::CreateDOMFactory(fnd.getAllocator(), strTable));
+ SAppXMLErrorHandler errorHandler(fnd, sourcePath.toUtf8().constData());
+ eastl::pair<SNamespacePairNode *, SDOMElement *> readResult =
+ CDOMSerializer::Read(*domFactory, inputStream, &errorHandler);
+ if (!readResult.second) {
+ qCCritical(INVALID_PARAMETER, "%s doesn't appear to be valid xml",
+ sourcePath.toUtf8().constData());
+ } else {
+ NVScopedRefCounted<IDOMReader> domReader = IDOMReader::CreateDOMReader(
+ fnd.getAllocator(), *readResult.second, strTable, domFactory);
+ if (m_visitor)
+ m_visitor->visit(sourcePath.toUtf8().constData());
+ retval = LoadUIA(*domReader, fnd);
+ }
+ } else {
+ qCCritical(INVALID_PARAMETER, "Unable to open input file %s",
+ sourcePath.toUtf8().constData());
+ }
+ } else {
+ QT3DS_ASSERT(false);
+ }
+ return retval;
+ }
+
+ void EndLoad() override
+ {
+ if (m_AppLoadContext)
+ m_AppLoadContext->EndLoad();
+ }
+
+ void RunAllRunnables()
+ {
+ {
+ Mutex::ScopedLock __locker(m_RunnableMutex);
+ m_MainThreadRunnables = m_ThreadRunnables;
+ m_ThreadRunnables.clear();
+ }
+ for (QT3DSU32 idx = 0, end = m_MainThreadRunnables.size(); idx < end; ++idx)
+ m_MainThreadRunnables[idx]->Run();
+ m_MainThreadRunnables.clear();
+ }
+
+ bool HasCompletedLoading() override
+ {
+ RunAllRunnables();
+ if (m_AppLoadContext)
+ return m_AppLoadContext->HasCompletedLoading();
+
+ return true;
+ }
+
+ bool createSuccessful() override
+ {
+ return m_createSuccessful;
+ }
+
+ // will force loading to end if endLoad hasn't been called yet. Will fire off loading
+ // of resources that need to be uploaded to opengl. Maintains reference to runtime factory
+ IApplication &CreateApplication(Q3DStudio::CInputEngine &inInputEngine,
+ Q3DStudio::IAudioPlayer *inAudioPlayer,
+ Q3DStudio::IRuntimeFactory &inFactory) override
+ {
+ {
+ SStackPerfTimer __loadTimer(m_CoreFactory->GetPerfTimer(),
+ "Application: Initialize Graphics");
+
+ {
+ SStackPerfTimer __timer(m_CoreFactory->GetPerfTimer(), "Application: EndLoad");
+ EndLoad();
+ }
+ m_InputEnginePtr = &inInputEngine;
+ m_RuntimeFactory = inFactory;
+
+ {
+ SStackPerfTimer __timer(m_CoreFactory->GetPerfTimer(),
+ "Application: Load Context Graphics Initialized");
+ if (m_AppLoadContext)
+ m_createSuccessful = m_AppLoadContext->OnGraphicsInitialized(inFactory);
+ // Guarantees the end of the multithreaded access to the various components
+ m_AppLoadContext = NULL;
+ if (!m_createSuccessful)
+ return *this;
+ }
+
+ {
+ SStackPerfTimer __loadTimer(m_CoreFactory->GetPerfTimer(),
+ "Application: End Font Preload");
+ if (m_CoreFactory->GetRenderContextCore().GetTextRendererCore())
+ m_CoreFactory->GetRenderContextCore()
+ .GetTextRendererCore()
+ ->EndPreloadFonts();
+ }
+
+ RunAllRunnables();
+ // Moving set application to the end ensures that the application load context is not
+ // accessing
+ // the lua state in another thread while we are calling set application. This
+ // apparently may cause
+ // the call to set application to fail miserably.
+ m_RuntimeFactory->SetApplication(this);
+ m_RuntimeFactory->GetStringTable().DisableMultithreadedAccess();
+
+ for (QT3DSU32 idx = 0, end = m_OrderedAssets.size(); idx < end; ++idx) {
+ if (m_OrderedAssets[idx].second->getType() == AssetValueTypes::Presentation) {
+ SPresentationAsset &theAsset(
+ *m_OrderedAssets[idx].second->getDataPtr<SPresentationAsset>());
+ CPresentation *thePresentation = theAsset.m_Presentation;
+ if (thePresentation) {
+ SStackPerfTimer __loadTimer(m_CoreFactory->GetPerfTimer(),
+ "Application: SetActivityZone");
+ thePresentation->SetActivityZone(
+ &m_ActivityZoneManager->CreateActivityZone(*thePresentation));
+ thePresentation->SetActive(theAsset.m_Active);
+ }
+ }
+ }
+
+ inInputEngine.SetApplication(this);
+ }
+ SApplicationSettings finalSettings(/*m_CommandLineSettings, */m_UIAFileSettings);
+ if (finalSettings.m_LayerCacheEnabled.hasValue()) {
+ inFactory.GetQt3DSRenderContext().GetRenderer().EnableLayerCaching(
+ *finalSettings.m_LayerCacheEnabled);
+ }
+ if (finalSettings.m_LayerGpuProfilingEnabled.hasValue()) {
+ inFactory.GetQt3DSRenderContext().GetRenderer().EnableLayerGpuProfiling(
+ *finalSettings.m_LayerGpuProfilingEnabled);
+ }
+
+ m_CoreFactory->GetPerfTimer().OutputTimerData();
+
+ m_AudioPlayer.SetPlayer(inAudioPlayer);
+
+ return *this;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Getters/Setters
+ //////////////////////////////////////////////////////////////////////////////////////////////////////
+ CRegisteredString RegisterStr(const char8_t *inStr)
+ {
+ return m_CoreFactory->GetStringTable().RegisterStr(inStr);
+ }
+
+ // The directory that contains the executable and the root resource path
+ CRegisteredString GetApplicationDirectory() const override
+ {
+ return const_cast<SApp &>(*this).m_CoreFactory->GetStringTable().RegisterStr(
+ m_ApplicationDir.c_str());
+ }
+ // Directory that contained the XIF file.
+ CRegisteredString GetProjectDirectory() const override
+ {
+ QT3DS_ASSERT(m_ProjectDir.size());
+ return const_cast<SApp &>(*this).m_CoreFactory->GetStringTable().RegisterStr(
+ m_ProjectDir.c_str());
+ }
+
+ CRegisteredString GetDllDir() const override
+ {
+ if (m_DLLDirectory.size()) {
+ return const_cast<SApp &>(*this).m_CoreFactory->GetStringTable().RegisterStr(
+ m_DLLDirectory.c_str());
+ }
+ return CRegisteredString();
+ }
+
+ void SetDllDir(const char *inDllDir) override
+ {
+ m_DLLDirectory.assign(nonNull(inDllDir));
+ m_CoreFactory->SetDllDir(inDllDir);
+ }
+
+ Q3DStudio::IRuntimeFactory &GetRuntimeFactory() const override { return *m_RuntimeFactory.mPtr; }
+ Q3DStudio::IRuntimeFactoryCore &GetRuntimeFactoryCore() override { return *m_CoreFactory; }
+
+ Q3DStudio::CPresentation *GetPrimaryPresentation() override
+ {
+ return GetPresentationById(m_InitialPresentationId.c_str());
+ }
+
+ Q3DStudio::CPresentation *GetPresentationById(const char8_t *inId) override
+ {
+ if (!isTrivial(inId)) {
+ TIdAssetMap::iterator iter
+ = m_AssetMap.find(m_CoreFactory->GetStringTable().RegisterStr(inId));
+ if (iter != m_AssetMap.end()
+ && iter->second->getType() == AssetValueTypes::Presentation) {
+ return iter->second->getData<SPresentationAsset>().m_Presentation;
+ }
+ }
+ return NULL;
+ }
+
+ // Returns a list of all presentations in the application
+ // The primary presentation is returned at index 0
+ QList<Q3DStudio::CPresentation *> GetPresentationList() override
+ {
+ QList<Q3DStudio::CPresentation *> list;
+ for (TIdAssetMap::iterator iter = m_AssetMap.begin(); iter != m_AssetMap.end(); ++iter) {
+ if (iter->second->getType() == AssetValueTypes::Presentation) {
+ Q3DStudio::CPresentation *presentation
+ = iter->second->getData<SPresentationAsset>().m_Presentation;
+ if (presentation) {
+ if (iter->first == m_InitialPresentationId)
+ list.prepend(presentation);
+ else
+ list.append(presentation);
+ }
+ }
+ }
+ return list;
+ }
+
+ template <typename TAssetType>
+ void RegisterAsset(const TAssetType &inAsset)
+ {
+ NVScopedRefCounted<SRefCountedAssetValue> theValue(
+ QT3DS_NEW(m_CoreFactory->GetFoundation().getAllocator(),
+ SRefCountedAssetValue(m_CoreFactory->GetFoundation(), inAsset)));
+ if (inAsset.m_Id.IsValid())
+ m_AssetMap.insert(eastl::make_pair(inAsset.m_Id, theValue));
+
+ m_OrderedAssets.push_back(eastl::make_pair(inAsset.m_Id, theValue));
+
+ if (m_visitor) {
+ m_visitor->visit(inAsset.Type(), inAsset.m_Id.c_str(), inAsset.m_Src.c_str(),
+ inAsset.m_Args.c_str());
+ }
+ }
+
+ THashValue HashString(const char *inStr) override
+ {
+ if (inStr == NULL)
+ inStr = "";
+ THashValue retval = CHash::HashString(inStr);
+ eastl::pair<THashStrMap::iterator, bool> insertResult
+ = m_HashStrMap.insert(eastl::make_pair(retval, CRegisteredString()));
+ if (insertResult.second)
+ insertResult.first->second = m_CoreFactory->GetStringTable().RegisterStr(inStr);
+ return retval;
+ }
+
+ const char *ReverseHash(THashValue theValue) override
+ {
+ THashStrMap::iterator find = m_HashStrMap.find(theValue);
+ if (find != m_HashStrMap.end())
+ return find->second.c_str();
+ return "";
+ }
+
+ void SetFrameCount(Q3DStudio::INT32 inFrameCount) override { m_FrameCount = inFrameCount; }
+
+ Q3DStudio::INT32 GetFrameCount() override { return m_FrameCount; }
+
+ void SetTimeMilliSecs(Q3DStudio::INT64 inMilliSecs) override { m_ManualTime = inMilliSecs; }
+
+ Q3DStudio::INT64 GetTimeMilliSecs() override
+ {
+ return m_ManualTime == 0 ? m_Timer.GetTimeMilliSecs() : m_ManualTime;
+ }
+
+ void ResetTime() override
+ {
+ m_Timer.Reset();
+ m_ManualTime = 0;
+ }
+
+ void HideFPS(bool flag) override { m_HideFPS = flag; }
+
+ Q3DStudio::CInputEngine &GetInputEngine() override
+ {
+ QT3DS_ASSERT(m_InputEnginePtr);
+ return *m_InputEnginePtr;
+ }
+
+ Q3DStudio::IRuntimeMetaData &GetMetaData() override
+ {
+ if (!m_MetaData) {
+ m_MetaData = &IRuntimeMetaData::Create(m_CoreFactory->GetInputStreamFactory());
+ if (!m_MetaData) {
+ qCCritical(qt3ds::INVALID_OPERATION)
+ << "IRuntimeMetaData::Create: Failed to create meta data";
+ }
+ }
+ return *m_MetaData;
+ }
+
+ qt3ds::state::debugger::IDebugger &GetStateDebugger() override
+ {
+ if (!m_StateDebugger)
+ m_StateDebugger = qt3ds::state::debugger::IDebugger::CreateDebugger();
+ return *m_StateDebugger;
+ }
+
+ qt3ds::state::debugger::ISceneGraphRuntimeDebugger &GetSceneGraphDebugger() override
+ {
+ if (!m_SceneGraphDebugger)
+ m_SceneGraphDebugger = qt3ds::state::debugger::ISceneGraphRuntimeDebugger::Create(
+ m_CoreFactory->GetFoundation(), m_CoreFactory->GetStringTable());
+ return *m_SceneGraphDebugger;
+ }
+
+ IActivityZoneManager &GetActivityZoneManager() override { return *m_ActivityZoneManager; }
+
+ IElementAllocator &GetElementAllocator() override { return *m_ElementAllocator; }
+
+ Q3DStudio::UINT32 GetHandleForElement(Q3DStudio::TElement *inElement) override
+ {
+ return inElement->GetHandle();
+ }
+
+ Q3DStudio::TElement *GetElementByHandle(Q3DStudio::UINT32 inHandle) override
+ {
+ return GetElementAllocator().FindElementByHandle(inHandle);
+ }
+};
+
+struct SXMLLoader : public IAppLoadContext
+{
+ SApp &m_App;
+ eastl::string m_ScaleMode;
+ eastl::vector<qt3ds::state::SElementReference> m_References;
+ QT3DSI32 mRefCount;
+
+ SXMLLoader(SApp &inApp, const char8_t *sc, NVConstDataRef<qt3ds::state::SElementReference> refs)
+ : m_App(inApp)
+ , m_ScaleMode(nonNull(sc))
+ , mRefCount(0)
+ {
+ m_References.assign(refs.begin(), refs.end());
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_App.m_CoreFactory->GetFoundation().getAllocator())
+
+ void EndLoad() override {}
+
+ bool HasCompletedLoading() override { return true; }
+
+ bool OnGraphicsInitialized(IRuntimeFactory &inFactory) override
+ {
+ eastl::vector<SElementAttributeReference> theUIPReferences;
+ eastl::string tempString;
+ for (QT3DSU32 idx = 0, end = m_App.m_OrderedAssets.size(); idx < end; ++idx) {
+ SAssetValue &theAsset = *m_App.m_OrderedAssets[idx].second;
+ eastl::string thePathStr;
+
+ CFileTools::CombineBaseAndRelative(m_App.GetProjectDirectory().c_str(),
+ theAsset.GetSource(), thePathStr);
+ switch (theAsset.getType()) {
+ case AssetValueTypes::Presentation: {
+ QDir::addSearchPath(QStringLiteral("qt3dstudio"),
+ QFileInfo(QString(thePathStr.c_str()))
+ .absoluteDir().absolutePath());
+ SPresentationAsset &thePresentationAsset
+ = *theAsset.getDataPtr<SPresentationAsset>();
+ theUIPReferences.clear();
+ for (QT3DSU32 refIdx = 0, refEnd = m_References.size(); refIdx < refEnd; ++refIdx) {
+ tempString.assign(m_References[refIdx].m_ElementPath.c_str());
+ eastl::string::size_type colonPos = tempString.find_first_of(':');
+ if (colonPos != eastl::string::npos) {
+ tempString = tempString.substr(0, colonPos);
+ if (tempString.compare(thePresentationAsset.m_Id.c_str()) == 0) {
+ SElementAttributeReference newReference(
+ m_References[refIdx].m_ElementPath.c_str() + colonPos + 1,
+ m_References[refIdx].m_Attribute.c_str());
+ theUIPReferences.push_back(newReference);
+ }
+ }
+ }
+
+ if (!m_App.LoadUIP(thePresentationAsset,
+ toConstDataRef(theUIPReferences.data(),
+ (QT3DSU32)theUIPReferences.size()))) {
+ qCCritical(INVALID_OPERATION, "Unable to load presentation %s",
+ thePathStr.c_str());
+ }
+ } break;
+ case AssetValueTypes::Behavior: {
+ SBehaviorAsset &theBehaviorAsset = *theAsset.getDataPtr<SBehaviorAsset>();
+ Q3DStudio::INT32 scriptId
+ = m_App.m_CoreFactory->GetScriptEngineQml().InitializeApplicationBehavior(
+ theBehaviorAsset.m_Src);
+ if (scriptId == 0) {
+ qCCritical(INVALID_OPERATION, "Unable to load application behavior %s",
+ theBehaviorAsset.m_Src.c_str());
+ } else {
+ theBehaviorAsset.m_Handle = scriptId;
+ m_App.m_Behaviors.push_back(eastl::make_pair(theBehaviorAsset, false));
+ }
+ } break;
+ case AssetValueTypes::RenderPlugin: {
+ SRenderPluginAsset &thePluginAsset = *theAsset.getDataPtr<SRenderPluginAsset>();
+
+ inFactory.GetSceneManager().LoadRenderPlugin(
+ thePluginAsset.m_Id, thePathStr.c_str(), thePluginAsset.m_Args);
+ } break;
+
+ case AssetValueTypes::QmlPresentation: {
+ SQmlPresentationAsset &asset = *theAsset.getDataPtr<SQmlPresentationAsset>();
+ inFactory.GetSceneManager().LoadQmlStreamerPlugin(asset.m_Id);
+ } break;
+ // SCXML, NoAssetValue do not need processing here
+ default:
+ break;
+ }
+ }
+ if (m_ScaleMode.empty() == false) {
+ const char8_t *initialScaleMode(m_ScaleMode.c_str());
+ // Force loading to finish here, just like used to happen.
+ if (AreEqual(initialScaleMode, "center")) {
+ inFactory.GetQt3DSRenderContext().SetScaleMode(qt3ds::render::ScaleModes::ExactSize);
+ } else if (AreEqual(initialScaleMode, "fit")) {
+ inFactory.GetQt3DSRenderContext().SetScaleMode(qt3ds::render::ScaleModes::ScaleToFit);
+ } else if (AreEqual(initialScaleMode, "fill")) {
+ inFactory.GetQt3DSRenderContext().SetScaleMode(qt3ds::render::ScaleModes::ScaleToFill);
+ } else {
+ qCCritical(INVALID_PARAMETER, "Unrecognized scale mode attribute value: ",
+ initialScaleMode);
+ }
+ }
+ return true;
+ }
+
+ virtual void OnFirstRender() {}
+};
+
+IAppLoadContext &IAppLoadContext::CreateXMLLoadContext(
+ SApp &inApp, NVConstDataRef<qt3ds::state::SElementReference> inStateReferences,
+ const char8_t *inScaleMode)
+{
+ return *QT3DS_NEW(inApp.m_CoreFactory->GetFoundation().getAllocator(),
+ SXMLLoader)(inApp, inScaleMode, inStateReferences);
+}
+}
+
+CAppStr::CAppStr(NVAllocatorCallback &alloc, const char8_t *inStr)
+ : TBase(inStr, ForwardingAllocator(alloc, "CAppStr"))
+{
+}
+
+CAppStr::CAppStr(const CAppStr &inOther)
+ : TBase(inOther)
+{
+}
+
+CAppStr::CAppStr()
+ : TBase()
+{
+}
+
+CAppStr &CAppStr::operator=(const CAppStr &inOther)
+{
+ TBase::operator=(inOther);
+ return *this;
+}
+
+IApplicationCore &IApplicationCore::CreateApplicationCore(Q3DStudio::IRuntimeFactoryCore &inFactory,
+ const char8_t *inApplicationDirectory)
+{
+ return *QT3DS_NEW(inFactory.GetFoundation().getAllocator(), SApp)(inFactory,
+ inApplicationDirectory);
+}
+
+// Checks if the event is one that can cause picking
+bool IApplicationCore::isPickingEvent(TEventCommandHash event)
+{
+ return (event == ON_MOUSEDOWN
+ || event == ON_MOUSEUP
+ || event == ON_MIDDLEMOUSEDOWN
+ || event == ON_MIDDLEMOUSEUP
+ || event == ON_RIGHTMOUSEDOWN
+ || event == ON_RIGHTMOUSEUP
+ || event == ON_MOUSECLICK
+ || event == ON_MIDDLEMOUSECLICK
+ || event == ON_RIGHTMOUSECLICK
+ || event == ON_MOUSEOVER
+ || event == ON_MOUSEOUT
+ || event == ON_GROUPEDMOUSEOVER
+ || event == ON_GROUPEDMOUSEOUT);
+}