/**************************************************************************** ** ** Copyright (C) 2017 The Qt Company Ltd. ** Contact: http://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 Q3DSENGINE_P_H #define Q3DSENGINE_P_H // // W A R N I N G // ------------- // // This file is not part of the Qt API. It exists purely as an // implementation detail. This header file may change from version to // version without notice, or even be removed. // // We mean it. // #include #include #include #include #include #include "q3dsuipdocument_p.h" #include "q3dsuiadocument_p.h" #include "q3dsdatainput.h" #include "q3dsuiaparser_p.h" #include "q3dsscenemanager_p.h" #include "private/q3dsbehaviorobject_p.h" #include "q3dssourceinfo_p.h" QT_BEGIN_NAMESPACE class QKeyEvent; class QMouseEvent; class QWheelEvent; class QTouchEvent; class QTabletEvent; class QQmlEngine; class QQmlComponent; class Q3DSInlineQmlSubPresentation; class Q3DSViewportSettings; namespace Qt3DRender { class QRenderCapture; class QRenderCaptureReply; namespace Quick { class QScene2D; } } struct Q3DSV_PRIVATE_EXPORT Q3DSBehaviorHandle { Q3DSBehaviorInstance *behaviorInstance = nullptr; QQmlComponent *component = nullptr; Q3DSBehaviorObject *object = nullptr; bool initialized = false; bool active = false; void updateProperties() const; }; struct Q3DSV_PRIVATE_EXPORT Q3DSRenderLoopStats { bool usingAsyncRenderAspect = false; bool usingSGRenderThread = false; float quickDeltaMs = 0; }; struct ParentChildPairs { QVector> m_parentChildPairs; void addPair(QObject *parent, QObject *child) { m_parentChildPairs.push_back(QPair(parent, child)); } }; class Q3DSV_PRIVATE_EXPORT Q3DSEngine : public QObject { Q_OBJECT public: Q3DSEngine(); ~Q3DSEngine(); enum Flag { Force4xMSAA = 0x01, EnableProfiling = 0x02, WithoutRenderAspect = 0x04, PreLoadSubPresentations = 0x08, AwakenTheDragon = 0x10 }; Q_DECLARE_FLAGS(Flags, Flag) static void clearLog(); Flags flags() const { return m_flags; } void setFlags(Flags flags); void setFlag(Flag flag, bool enabled); void setSharedSubPresentationQmlEngine(QQmlEngine *qmlEngine); void setSharedBehaviorQmlEngine(QQmlEngine *qmlEngine); static void setQmlProfileUiInstance(QObject *imguiItem) { m_imguiItem = imguiItem; } static QObject *qmlProfileUiInstance() { return m_imguiItem; } using InlineSubPresList = QVector; // Load presentation from a uip/uia file. bool setSource(const Q3DSSourceInfo &sourceInfo, QString *error = nullptr, const InlineSubPresList &inlineQmlSubPresentations = InlineSubPresList()); Q3DSSourceInfo source() const; // Load presentation from a uip document object. bool setDocument(const Q3DSUipDocument &uipDocument, QString *error = nullptr); // Load presentation from a uia document object. bool setDocument(const Q3DSUiaDocument &uiaDocument, QString *error = nullptr); // Provide a pre-constructed presentation. Entry point for programatically // constructed scenes. bool setPresentation(Q3DSUipPresentation *presentations); // Start animating all uip presentations. void startAnimations(); qint64 behaviorLoadTimeMsecs() const; qint64 totalLoadTimeMsecs() const; int presentationCount() const; QString uipFileName(int index = 0) const; Q3DSUipDocument *uipDocument(int index = 0) const; Q3DSUipPresentation *presentation(int index = 0) const; Q3DSUipPresentation *presentationByName(const QString &name) const; Q3DSSceneManager *sceneManager(int index = 0) const; Qt3DCore::QAspectEngine *aspectEngine() const; Qt3DCore::QEntity *rootEntity() const; Q3DSViewportSettings *viewportSettings() const; void setViewportSettings(Q3DSViewportSettings *viewportSettings); void setOnDemandRendering(bool enabled); void setMainLayerComposition(bool enabled); void setDelayedLoading(bool enable); QSize implicitSize() const; void setSurface(QObject *surface); QObject *surface() const; bool start(); void resize(const QSize &size, qreal dpr = qreal(1.0), bool forceSynchronous = false); void setDataInputValue(const QString &name, const QVariant &value); void setDataInputMin(const QString &name, float min); void setDataInputMax(const QString &name, float max); QVector dataInputs(); QVector dataInputs(const QVariant &metadataKey); bool isValidDataInput(const Q3DSDataInput *di) const; QVariant dataInputMetaData(const Q3DSDataInput *di, const QVariant &key) const; QList dataInputMetaDataKeys(const Q3DSDataInput *di) const; void setDataInputMetaData(const QString &diName, const QVariant &key, const QVariant &metaData); void removeDatainputMetadata(const QString &name, const QVariant &key); float dataInputMin(const QString &name) const; float dataInputMax(const QString &name) const; void fireEvent(Q3DSGraphObject *target, Q3DSUipPresentation *presentation, const QString &event); void goToTime(Q3DSGraphObject *context, Q3DSUipPresentation *presentation, float milliseconds); void goToSlideByName(Q3DSGraphObject *context, Q3DSUipPresentation *presentation, const QString &name); void goToSlideByIndex(Q3DSGraphObject *context, Q3DSUipPresentation *presentation, int index); void goToSlideByDirection(Q3DSGraphObject *context, Q3DSUipPresentation *presentation, bool next, bool wrap); void preloadSlide(Q3DSSlide *slide, Q3DSUipPresentation *presentation); void unloadSlide(Q3DSSlide *slide, Q3DSUipPresentation *presentation); void handleKeyPressEvent(QKeyEvent *e); void handleKeyReleaseEvent(QKeyEvent *e); void handleMousePressEvent(QMouseEvent *e, Q3DSLayerNode *targetLayer = nullptr); void handleMouseMoveEvent(QMouseEvent *e, Q3DSLayerNode *targetLayer = nullptr); void handleMouseReleaseEvent(QMouseEvent *e, Q3DSLayerNode *targetLayer = nullptr); void handleMouseDoubleClickEvent(QMouseEvent *e, Q3DSLayerNode *targetLayer = nullptr); #if QT_CONFIG(wheelevent) void handleWheelEvent(QWheelEvent *e, Q3DSLayerNode *targetLayer = nullptr); #endif void handleTouchEvent(QTouchEvent *e, Q3DSLayerNode *targetLayer = nullptr); #if QT_CONFIG(tabletevent) void handleTabletEvent(QTabletEvent *e, Q3DSLayerNode *targetLayer = nullptr); #endif void setAutoToggleProfileUi(bool enabled) { m_autoToggleProfileUi = enabled; } void setProfileUiVisible(bool visible, bool openLogAndConsole = false); bool isStereoscopic() const; bool isProfileUiVisible() const; bool isAnimatorsReady() const; void configureProfileUi(float scale); float profileUiScaleFactor() const { return m_profileUiScale; } typedef QHash BehaviorMap; typedef std::function BehaviorLoadedCallback; void loadBehaviorInstance(Q3DSBehaviorInstance *behaviorInstance, Q3DSUipPresentation *pres, BehaviorLoadedCallback callback = nullptr); void unloadBehaviorInstance(Q3DSBehaviorInstance *behaviorInstance); const BehaviorMap &behaviorHandles() const { return m_behaviorHandles; } // These two functions are the only place where the elementPath concept is // present in the engine (so that mappings can be made for the 3DS1-style // APIs). Proper objects must be used everywhere else. Q3DSGraphObject *findObjectByHashIdOrNameOrPath(Q3DSGraphObject *thisObject, Q3DSUipPresentation *defaultPresentation, const QString &idOrNameOrPath, Q3DSUipPresentation **actualPresentation = nullptr); QString makePath(Q3DSGraphObject *obj) const; Qt3DCore::QNodeId layerTextureNodeId(Q3DSLayerNode *layer3DS) const; void reportQuickRenderLoopStats(float deltaMs, bool isThreaded); Q3DSRenderLoopStats renderLoopStats(); Q3DSSubPresentation loadSubUipPresentation(const QString &subPresId); template Q3DSSubPresentation loadSubUipPresentation(const QString &subPresId, FinalizeFunc finalize, Params... params) { Q3DSSubPresentation sp; SceneLoaderAsync *loader = nullptr; UipPresentation *uip = nullptr; for (int i = 0; i < m_uipPresentations.count(); ++i) { if (m_uipPresentations[i].subPres.id == subPresId) { uip = &m_uipPresentations[i]; break; } } if (!uip) return sp; loader = new SceneLoaderAsync; loader->function = [loader, finalize, params...]() { loader->reparentChildren(); finalize(&loader->sp, params...); }; loader->pres = uip; beginAsyncLoad(sp, loader); return sp; } void finishAsyncLoad(bool wait = true); void loadSlideResources(Q3DSSlide *slide, Q3DSUipPresentation *presentation); void unloadSlideResources(Q3DSSlide *slide, Q3DSUipPresentation *presentation); void createAspectEngine(); public Q_SLOTS: void requestGrab(); Q_SIGNALS: void presentationLoaded(); void nextFrameStarting(); void grabReady(const QImage &image); void customSignalEmitted(Q3DSGraphObject *obj, const QString &name); void slideEntered(Q3DSGraphObject *context, int index, const QString &name); void slideExited(Q3DSGraphObject *context, int index, const QString &name); void layerResized(Q3DSLayerNode *layer3DS); void layerTextureNodeChanged(Q3DSLayerNode *layer3DS); void stereoModeChanged(); private: Q_DISABLE_COPY(Q3DSEngine) struct Presentation { Q3DSSubPresentation subPres; }; struct UipPresentation : Presentation { Q3DSUipDocument *uipDocument = nullptr; Q3DSSceneManager::Scene q3dscene; Q3DSSceneManager *sceneManager = nullptr; Q3DSUipPresentation *presentation = nullptr; }; struct QmlPresentation : Presentation { // we have either a QmlDocument with the source or filename, or an // inline subpresentation object with a QQuickItem* in it Q3DSQmlDocument *qmlDocument = nullptr; Q3DSInlineQmlSubPresentation *inlineQmlSubPres = nullptr; Qt3DRender::Quick::QScene2D *scene2d = nullptr; }; struct SceneLoaderAsync : public ParentChildPairs { QThread *targetThread; QFuture future; UipPresentation *pres; std::function function; Q3DSSubPresentation sp; bool done; SceneLoaderAsync() : targetThread(nullptr), pres(nullptr), done(false) {} SceneLoaderAsync(const SceneLoaderAsync &loader) : ParentChildPairs(loader), targetThread(loader.targetThread), future(loader.future), pres(loader.pres), function(loader.function), sp(loader.sp), done(loader.done) {} void reparentChildren(); }; void beginAsyncLoad(Q3DSSubPresentation &sp, SceneLoaderAsync *loader); void finishAsyncLoadForSubpresentation(const QString &name); void reparentScene(SceneLoaderAsync *loader); struct SlideResourceCounter { QHash counters; QSet createSet; QSet deleteSet; QVector loadedSlides; void increment(const QSet &set) { for (auto &r : set) { if (counters.value(r, 0) == 0) createSet.insert(r); counters[r]++; } } void decrement(const QSet &set) { for (auto &r : set) { if (counters.contains(r)) { int count = qMax(counters[r] - 1, 0); if (count == 0) deleteSet.insert(r); counters[r] = count; } } } void begin() { createSet.clear(); deleteSet.clear(); } void reset() { loadedSlides.clear(); counters.clear(); begin(); } void handleLoadSlide(Q3DSSlide *slide, Q3DSUipPresentation *presentation) { if (loadedSlides.contains(slide)) return; slide->generateResourceSet(presentation); loadedSlides.push_back(slide); begin(); increment(slide->resourceSet()); print(); } void handleUnloadSlide(Q3DSSlide *slide, Q3DSUipPresentation *presentation) { if (!loadedSlides.contains(slide)) return; slide->generateResourceSet(presentation); loadedSlides.removeOne(slide); begin(); decrement(slide->resourceSet()); print(); } void print(); }; bool loadPresentations(); void finalizePresentations(); bool loadUipPresentation(UipPresentation *pres); bool buildUipPresentationScene(UipPresentation *pres); bool loadSubUipPresentation(UipPresentation *pres); bool buildSubUipPresentationScene(UipPresentation *pres, SceneLoaderAsync *loader = nullptr); bool loadSubQmlPresentation(QmlPresentation *pres); bool parseUipDocument(UipPresentation *pres); bool parseUiaDocument(Q3DSUiaParser::Uia &uiaDoc, const QString &sourcePrefix); void destroy(); void prepareForReload(); void loadBehaviors(); void destroyBehaviorHandle(const Q3DSBehaviorHandle &h); void behaviorFrameUpdate(float dt); QRect calculateViewport(const QSize &surfaceSize, const QSize &presentationSize) const; void registerQmlTypes(); void initializeDataInputs(); QObject *m_surface = nullptr; QSize m_implicitSize; QSize m_size; qreal m_dpr = 1; Flags m_flags; Q3DSSourceInfo m_sourceInfo; // uip or uia file + variant info QVector m_uipPresentations; QVector m_qmlPresentations; QVector m_inlineQmlPresentations; Q3DSDataInputEntry::Map m_dataInputEntries; Q3DSDataInputEntry::MetadataMap m_dataInputMetaData; // In addition to datainput bookkeeping data, let engine instantiate // and manage actual datainput objects created. This removes the need // to create datainputs on-the-fly when Q3DSPresentation API client // requests a list of datainputs QVector m_dataInputs; QQmlEngine *m_qmlSubPresentationEngine = nullptr; bool m_ownsQmlSubPresentationEngine = false; QScopedPointer m_aspectEngine; qint64 m_loadTime = 0; qint64 m_behaviorLoadTime = 0; QElapsedTimer m_profilerActivateTimer; QElapsedTimer m_sourceLoadTimer; Qt3DRender::QRenderCapture *m_capture = nullptr; QHash m_captureConnections; QObject m_profileUiEventSource; float m_profileUiScale = 1.0f; bool m_autoToggleProfileUi = true; QQmlEngine *m_behaviorQmlEngine = nullptr; bool m_ownsBehaviorQmlEngine = false; BehaviorMap m_behaviorHandles; bool m_onDemandRendering = false; bool m_mainLayerComposition = true; Q3DSViewportSettings *m_viewportSettings = nullptr; static QObject *m_imguiItem; Q3DSRenderLoopStats m_renderLoopStats; QMutex m_renderLoopStatsMutex; float m_quickDeltaSum = 0; int m_quickDeltaCount = 0; QVector m_asyncSceneLoaders; SlideResourceCounter m_resourceReferenceCounter; QMutex *m_slideResourceMutex = nullptr; QMutex *m_asyncLoadMutex= nullptr; }; Q_DECLARE_OPERATORS_FOR_FLAGS(Q3DSEngine::Flags) QT_END_NAMESPACE #endif // Q3DSENGINE_P_H