diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-11-15 15:00:09 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-11-16 10:19:47 +0000 |
commit | 0e5983e737abcd664e07f22da342f1ae41b52124 (patch) | |
tree | b0d04b197bc46fff113192f87a88d01adaa4a524 | |
parent | b8e880e432e5cc640ba1cd95a85ca36c5a1a9a61 (diff) |
Add a way to hook into the private API, with example and docsv2.2.0-beta1
Change-Id: Ib46f4e753964eaad02f455f80962321fb64496c4
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
-rw-r--r-- | examples/3dstudioruntime2/3dstudioruntime2.pro | 3 | ||||
-rw-r--r-- | examples/3dstudioruntime2/scenemanip/doc/images/scenemanip.png | bin | 0 -> 41349 bytes | |||
-rw-r--r-- | examples/3dstudioruntime2/scenemanip/doc/src/scenemanip.qdoc | 46 | ||||
-rw-r--r-- | examples/3dstudioruntime2/scenemanip/empty.uia | 15 | ||||
-rw-r--r-- | examples/3dstudioruntime2/scenemanip/main.cpp | 155 | ||||
-rw-r--r-- | examples/3dstudioruntime2/scenemanip/main.qml | 74 | ||||
-rw-r--r-- | examples/3dstudioruntime2/scenemanip/presentations/empty.uip | 31 | ||||
-rw-r--r-- | examples/3dstudioruntime2/scenemanip/scenemanip.pro | 14 | ||||
-rw-r--r-- | examples/3dstudioruntime2/scenemanip/scenemanip.qrc | 7 | ||||
-rw-r--r-- | src/runtime/api/q3dspresentation.cpp | 17 | ||||
-rw-r--r-- | src/runtime/api/q3dspresentation.h | 3 | ||||
-rw-r--r-- | src/runtime/api/q3dspresentation_p.h | 2 | ||||
-rw-r--r-- | src/runtime/doc/src/examples.qdoc | 1 | ||||
-rw-r--r-- | src/runtime/doc/src/index.qdoc | 1 | ||||
-rw-r--r-- | src/runtime/doc/src/scenecppapi.qdoc | 247 |
15 files changed, 615 insertions, 1 deletions
diff --git a/examples/3dstudioruntime2/3dstudioruntime2.pro b/examples/3dstudioruntime2/3dstudioruntime2.pro index 37e384d..d03ce05 100644 --- a/examples/3dstudioruntime2/3dstudioruntime2.pro +++ b/examples/3dstudioruntime2/3dstudioruntime2.pro @@ -7,7 +7,8 @@ SUBDIRS += \ qtHaveModule(quick) { SUBDIRS += simpleqml \ qmldatainput \ - layersinquick + layersinquick \ + scenemanip } qtHaveModule(widgets) { diff --git a/examples/3dstudioruntime2/scenemanip/doc/images/scenemanip.png b/examples/3dstudioruntime2/scenemanip/doc/images/scenemanip.png Binary files differnew file mode 100644 index 0000000..cdc5311 --- /dev/null +++ b/examples/3dstudioruntime2/scenemanip/doc/images/scenemanip.png diff --git a/examples/3dstudioruntime2/scenemanip/doc/src/scenemanip.qdoc b/examples/3dstudioruntime2/scenemanip/doc/src/scenemanip.qdoc new file mode 100644 index 0000000..871c57d --- /dev/null +++ b/examples/3dstudioruntime2/scenemanip/doc/src/scenemanip.qdoc @@ -0,0 +1,46 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \example scenemanip + \title Qt 3D Studio Runtime: Dynamic Scene Manipulation C++ Example + \ingroup qt3dstudioruntime2-examples-cpp + \brief Demonstrates using the private C++ APIs to change the scene at run time + + \image scenemanip.png + + \e {This example demonstrates basic usage of the Qt 3D Studio runtime's + private C++ APIs in order to change the scene at run time.} + + \include examples-run.qdocinc + + This example uses the private C++ APIs from the Qt 3D Studio Runtime in + order to programatically create models and materials in a Qt 3D Studio + scene loaded from a \c{.uip} file into a Studio3D item inside a Qt Quick + scene. It also demonstrates connecting QML and C++ logic to events that + occur when an object is picked in the 3D scene. +*/ diff --git a/examples/3dstudioruntime2/scenemanip/empty.uia b/examples/3dstudioruntime2/scenemanip/empty.uia new file mode 100644 index 0000000..85e47c3 --- /dev/null +++ b/examples/3dstudioruntime2/scenemanip/empty.uia @@ -0,0 +1,15 @@ +<?xml version='1.0' encoding='utf-8'?> +<application xmlns="http://qt.io/qt3dstudio/uia"> + <assets initial="empty"> + <presentation src="presentations/empty.uip" id="empty"/> + </assets> + <statemachine ref="#logic"> + <visual-states> + <state ref="Initial"> + <enter> + <goto-slide element="main:Scene" rel="next"/> + </enter> + </state> + </visual-states> + </statemachine> +</application> diff --git a/examples/3dstudioruntime2/scenemanip/main.cpp b/examples/3dstudioruntime2/scenemanip/main.cpp new file mode 100644 index 0000000..a59c123 --- /dev/null +++ b/examples/3dstudioruntime2/scenemanip/main.cpp @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QGuiApplication> +#include <QQmlContext> +#include <QQuickView> +#include <QTime> +#include <QTimer> +#include <Q3DSPresentation> + +#include <private/q3dsengine_p.h> +#include <private/q3dsuippresentation_p.h> + +class SceneManipulator : public QObject +{ + Q_OBJECT + +public slots: + void doIt(Q3DSPresentation *pres); + +private: + QTimer m_timer; + int m_dynCount = 0; +}; + +void SceneManipulator::doIt(Q3DSPresentation *pres) +{ + Q3DSEngine *engine = pres->engine(); + Q3DSUipPresentation *presentation = engine->presentation(); + Q3DSSlide *slide1 = static_cast<Q3DSSlide *>(presentation->masterSlide()->firstChild()); + + Q3DSModelNode *prim = presentation->newObject<Q3DSModelNode>(QByteArrayLiteral("dynmodel") + QByteArray::number(m_dynCount)); + switch (qrand() % 4) { + case 0: + prim->setMesh(QLatin1String("#Cube")); + break; + case 1: + prim->setMesh(QLatin1String("#Sphere")); + break; + case 2: + prim->setMesh(QLatin1String("#Cylinder")); + break; + case 3: + prim->setMesh(QLatin1String("#Cone")); + break; + } + + Q3DSDefaultMaterial *primMat = presentation->newObject<Q3DSDefaultMaterial>(QByteArrayLiteral("dynmat") + QByteArray::number(m_dynCount)); + prim->appendChildNode(primMat); + + prim->setPosition(QVector3D((qrand() % 600) - 300, (qrand() % 600) - 300, 0)); + prim->setRotation(QVector3D(30, 45, 0)); + const float scale = ((qrand() % 100) + 1) / 100.0f; + prim->setScale(QVector3D(scale, scale, scale)); + + slide1->addObject(primMat); + slide1->addObject(prim); + + ++m_dynCount; + + // go live + presentation->objectByName<Q3DSLayerNode>(QLatin1String("Layer"))->appendChildNode(prim); + + // Animations cannot be managed dynamically for now. However, nothing + // prevents us from changing properties as we see fit: + m_timer.setInterval(30); + connect(&m_timer, &QTimer::timeout, this, [prim] { + QVector3D v = prim->position(); + v.setX(v.x() - 1); + QVector3D r = prim->rotation(); + r.setY(r.y() + 1); + prim->notifyPropertyChanges({ + prim->setPosition(v), + prim->setRotation(r) + }); + }); + m_timer.start(); +} + +int main(int argc, char *argv[]) +{ + QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + qputenv("QSG_INFO", "1"); + QGuiApplication app(argc, argv); + + qsrand(QTime::currentTime().msec()); + + // Use the ideal format (i.e. OpenGL version and profile) recommended by + // the Qt 3D Studio runtime. Without this the format set on the QQuickView + // would be used instead. + QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat()); + + QQuickView viewer; + + SceneManipulator manip; + viewer.rootContext()->setContextProperty("sceneManipulator", &manip); + + viewer.setSource(QUrl("qrc:/main.qml")); + + viewer.setTitle(QStringLiteral("Qt 3D Studio Example")); + viewer.setResizeMode(QQuickView::SizeRootObjectToView); + viewer.resize(1280, 720); + viewer.show(); + + return app.exec(); +} + +#include "main.moc" diff --git a/examples/3dstudioruntime2/scenemanip/main.qml b/examples/3dstudioruntime2/scenemanip/main.qml new file mode 100644 index 0000000..65d1412 --- /dev/null +++ b/examples/3dstudioruntime2/scenemanip/main.qml @@ -0,0 +1,74 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:BSD$ +** 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. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +import QtQuick 2.0 +import QtStudio3D 2.2 +import QtQuick.Window 2.3 + +Rectangle { + id: root + color: "lightGray" + + Studio3D { + id: s3d + focus: true + anchors.margins: 20 + anchors.fill: parent + + Presentation { + id: s3dpres + source: "qrc:/empty.uia" + onCustomSignalEmitted: { + if (name === "doIt") + sceneManipulator.doIt(s3dpres); + } + } + } +} diff --git a/examples/3dstudioruntime2/scenemanip/presentations/empty.uip b/examples/3dstudioruntime2/scenemanip/presentations/empty.uip new file mode 100644 index 0000000..3af7649 --- /dev/null +++ b/examples/3dstudioruntime2/scenemanip/presentations/empty.uip @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<UIP version="4" > + <Project > + <ProjectSettings author="" company="" presentationWidth="1280" presentationHeight="720" maintainAspect="False" > + <CustomColors count="16" >#ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors> + </ProjectSettings> + <Graph > + <Scene id="Scene" > + <Layer id="Layer" > + <Camera id="Camera" /> + <Light id="Light" /> + <Text id="Text" /> + </Layer> + </Scene> + </Graph> + <Logic > + <State name="Master Slide" component="#Scene" > + <Add ref="#Layer" /> + <Add ref="#Camera" /> + <Add ref="#Light" /> + <State id="Scene-Slide1" name="Slide1" > + <Add ref="#Text" name="Text" font="TitilliumWeb-Regular" position="31.7543 285.788 0" textstring="Click this to dynamically change the scene" > + <Action id="Text-Action" eyeball="True" triggerObject="#Text" event="onPressureDown" targetObject="#Text" handler="Emit Signal" > + <HandlerArgument name="Signal Name" type="String" argtype="Signal" value="doIt" /> + </Action> + </Add> + </State> + </State> + </Logic> + </Project> +</UIP> diff --git a/examples/3dstudioruntime2/scenemanip/scenemanip.pro b/examples/3dstudioruntime2/scenemanip/scenemanip.pro new file mode 100644 index 0000000..0e462e5 --- /dev/null +++ b/examples/3dstudioruntime2/scenemanip/scenemanip.pro @@ -0,0 +1,14 @@ +TEMPLATE = app + +QT += quick 3dstudioruntime2-private + +SOURCES += \ + main.cpp + +RESOURCES += scenemanip.qrc + +OTHER_FILES += \ + main.qml + +target.path = $$[QT_INSTALL_EXAMPLES]/3dstudioruntime2/$$TARGET +INSTALLS += target diff --git a/examples/3dstudioruntime2/scenemanip/scenemanip.qrc b/examples/3dstudioruntime2/scenemanip/scenemanip.qrc new file mode 100644 index 0000000..1c1313a --- /dev/null +++ b/examples/3dstudioruntime2/scenemanip/scenemanip.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/"> + <file>main.qml</file> + <file>empty.uia</file> + <file>presentations/empty.uip</file> + </qresource> +</RCC> diff --git a/src/runtime/api/q3dspresentation.cpp b/src/runtime/api/q3dspresentation.cpp index 3a8e37e..db2f77a 100644 --- a/src/runtime/api/q3dspresentation.cpp +++ b/src/runtime/api/q3dspresentation.cpp @@ -633,6 +633,23 @@ void Q3DSPresentation::tabletEvent(QTabletEvent *e) } #endif +/*! + Returns the underlying Q3DSEngine. See \l{Advanced Scene Manipulation via + the Qt 3D Studio Runtime Private C++ Classes} for details on using such + private APIs. + + The engine is only available when a presentation is loaded, the return + value is \c null otherwise. + */ +Q3DSEngine *Q3DSPresentation::engine() const +{ + Q_D(const Q3DSPresentation); + if (d->controller && !d->source.isEmpty()) + return d->controller->pcEngine(); + + return nullptr; +} + void Q3DSPresentationPrivate::setController(Q3DSPresentationController *c) { if (controller == c) diff --git a/src/runtime/api/q3dspresentation.h b/src/runtime/api/q3dspresentation.h index 898eef8..3ee3aaf 100644 --- a/src/runtime/api/q3dspresentation.h +++ b/src/runtime/api/q3dspresentation.h @@ -43,6 +43,7 @@ class QMouseEvent; class QWheelEvent; class QTouchEvent; class QTabletEvent; +class Q3DSEngine; // hack. no clue why Cpp.ignoretokens does not work. #ifdef Q_CLANG_QDOC @@ -105,6 +106,8 @@ public: void tabletEvent(QTabletEvent *e); #endif + Q3DSEngine *engine() const; + Q_SIGNALS: void sourceChanged(); void profilingEnabledChanged(); diff --git a/src/runtime/api/q3dspresentation_p.h b/src/runtime/api/q3dspresentation_p.h index 63c0f9a..56859a5 100644 --- a/src/runtime/api/q3dspresentation_p.h +++ b/src/runtime/api/q3dspresentation_p.h @@ -95,6 +95,8 @@ public: bool compareElementPath(const QString &a, const QString &b) const; + Q3DSEngine *pcEngine() const { return m_pcEngine; } + protected: Q3DSEngine *m_pcEngine = nullptr; // don't want clashes with commonly used m_engine members QVector<QPair<QString, QVariant> > m_pendingDataInputSets; diff --git a/src/runtime/doc/src/examples.qdoc b/src/runtime/doc/src/examples.qdoc index 209f34d..e054410 100644 --- a/src/runtime/doc/src/examples.qdoc +++ b/src/runtime/doc/src/examples.qdoc @@ -48,6 +48,7 @@ \li \l {Qt 3D Studio Runtime: Simple Window Example} \li \l {Qt 3D Studio Runtime: Simple Widget Example} \li \l {Qt 3D Studio Runtime: Simple Offscreen Example} + \li \l {Qt 3D Studio Runtime: Dynamic Scene Manipulation C++ Example} \endlist \section1 More Examples diff --git a/src/runtime/doc/src/index.qdoc b/src/runtime/doc/src/index.qdoc index 387e86f..8ca579a 100644 --- a/src/runtime/doc/src/index.qdoc +++ b/src/runtime/doc/src/index.qdoc @@ -37,6 +37,7 @@ \li \l {Qt 3D Studio Runtime C++ Classes} \li \l {Qt 3D Studio Runtime QML Types} \li \l {Attribute Names}{Scene Object Attribute List} + \li \l {Advanced Scene Manipulation via the Qt 3D Studio Runtime Private C++ Classes} \li \l {Using the In-Scene Debug and Profile views} \li \l {Examples} \li \l {Copyright Notices} diff --git a/src/runtime/doc/src/scenecppapi.qdoc b/src/runtime/doc/src/scenecppapi.qdoc new file mode 100644 index 0000000..4c0b622 --- /dev/null +++ b/src/runtime/doc/src/scenecppapi.qdoc @@ -0,0 +1,247 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt 3D Studio. +** +** $QT_BEGIN_LICENSE:FDL$ +** 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 Free Documentation License Usage +** Alternatively, this file may be used under the terms of the GNU Free +** Documentation License version 1.3 as published by the Free Software +** Foundation and appearing in the file included in the packaging of +** this file. Please review the following information to ensure +** the GNU Free Documentation License version 1.3 requirements +** will be met: https://www.gnu.org/licenses/fdl-1.3.html. +** $QT_END_LICENSE$ +** +****************************************************************************/ + +/*! + \page qt3d-runtime-scenecppapi.html + \title Advanced Scene Manipulation via the Qt 3D Studio Runtime Private C++ Classes + + In addition to the \l {Qt 3D Studio Runtime C++ Classes}}{public C++ API}, + applications needing direct access to the scenegraph of the presentations + loaded from \c{.uip} files can use the runtime's private C++ classes. + + \note These classes offer no source or binary compatibility guarantees. + + \note There is no documentation provided for the private classes. Refer to + the examples, this page, and the header files instead. + + To link against the module, add this line to your \l qmake \c .pro file: + + \badcode + QT += 3dstudioruntime2-private + \endcode + + Then add the following include statement to the application sources: + + \badcode + #include <private/q3dsengine_p.h> + #include <private/q3dsuippresentation_p.h> + \endcode + + To access the Q3DSEngine instance, call Q3DSPresentation::engine(). This + applies also to Qt Quick applications: the Presentation item in the QML + code is an instance of a subclass of Q3DSPresentation, so once it gets + passed to C++ code, it can be used as a Q3DSPresentation. Accessing the + engine is only possible when a presentation is loaded. If the code needing + access to the scene is not invoked by some user interaction but rather has + to be done at startup, connect the execution of the C++ logic to a signal + like Studio3D::presentationLoaded(). + + Check out the \l{Qt 3D Studio Runtime: Dynamic Scene Manipulation C++ + Example}{scenemanip example} for a demonstration of manipulating the Qt 3D + Studio scene from C++ in a Qt Quick application. + + The next step is to get access to the Qt 3D Studio object tree. Query the + Q3DSUipPresentation via Q3DSEngine::presentation(). There is a separate + object tree for each subpresentation. Q3DSEngine::presentationCount() + allows iterating through all of them: + + \badcode + int presentationCount() const; + Q3DSUipPresentation *presentation(int index = 0) const; + Q3DSUipPresentation *presentationByName(const QString &name) const; + \endcode + + The Q3DSUipPresentation instance owns two object trees: one for the scene + (that maps mostly 1:1 to the scene, layer, camera, light, model, etc. tree + in the left side of the Timline in the Qt 3D Studio editor) and one for the + slides. + + To access these, use the following accessors: + + \badcode + Q3DSScene *scene() const; + Q3DSSlide *masterSlide() const; + \endcode + + Support for dynamically manipulating the slide structure is limited as of + now. Certain related operations, like adding or removing animation tracks + at runtime is also limited for the time being. For the rest of this + document, we will focus on the scene itself. + + The scenegraph is quite similar to the Qt Quick scenegraph and QSGNode when + it comes to the management of child and sibling nodes. Adding and removing + child nodes happens using a very similar API. The equivalent of QSGNode in + the Qt 3D Studio world is Q3DSGraphObject. For application purposes the + most important member functions are: + + \badcode + Type type() const + Q3DSGraphObject *parent() const + Q3DSGraphObject *firstChild() const + Q3DSGraphObject *lastChild() const + Q3DSGraphObject *nextSibling() const + Q3DSGraphObject *previousSibling() const + int childCount() const; + Q3DSGraphObject *childAtIndex(int idx) const; + void removeChildNode(Q3DSGraphObject *node); + void removeAllChildNodes(); + void prependChildNode(Q3DSGraphObject *node); + void appendChildNode(Q3DSGraphObject *node); + void insertChildNodeBefore(Q3DSGraphObject *node, Q3DSGraphObject *before); + void insertChildNodeAfter(Q3DSGraphObject *node, Q3DSGraphObject *after); + void reparentChildNodesTo(Q3DSGraphObject *newParent); + + virtual void applyPropertyChanges(const Q3DSPropertyChangeList &changeList); + void notifyPropertyChanges(const Q3DSPropertyChangeList &changeList, int changeFlags = -1); + + QVector<QByteArray> propertyNames() const; + QVector<QVariant> propertyValues() const; + + QVariant property(const char *name); + bool setProperty(const char *name, const QVariant &v); + QVector<QByteArray> dynamicPropertyNames() const; + QVector<QVariant> dynamicPropertyValues() const; + + QVariantMap dynamicProperties() const; + void clearDynamicProperties(); + Q3DSPropertyChangeList applyDynamicProperties(const QVariantMap &v); + \endcode + + Q3DSLayerNode, Q3DSCameraNode, Q3DSLightNode, Q3DSModelNode, Q3DSGroupNode, + Q3DSTextNode are all subclasses of Q3DSNode which in turn is a + Q3DSGraphObject. The common base (Q3DSNode) provides common properties like + the transformation (position, rotation, scale). + + To change a property at runtime, first find out the correct name for the + property from the \l {Attribute Names}{Scene Object Attribute List}. + + Then do either + + \badcode + node->notifyPropertyChanges({ node->setPosition(QVector3D(1.0f, 0.5f, 3.0f)) }); + \endcode + + or + + \badcode + Q3DSPropertyChangeList cl { Q3DSPropertyChange::fromVariant("position", QVector3D(1.0f, 0.5f, 3.0f) }; + node->applyPropertyChanges(cl); + node->notifyPropertyChanges(cl); + \endcode + + The former is more efficient, while the latter allows constructing change + lists dynamically with the property names given as strings instead of + having to call C++ setter functions. + + To get access to an object, for example, the Q3DSModelNode corresponding to + a Model in the editor, use the Q3DSUipPresentation's object() or + objectByName() functions. The latter is more useful for applications since + it works based on the Name (that is defined by the designer in the editor), + while the former uses the object id that is unique, but invisible to the + designer in the editor. + + \note Names do not have to be unique. This can cause confusion because some + names the editor assigns by default are shared between multiple objects. To + prevent this, rename the objects in the tree view to something unique. + + \badcode + auto car = presentation->objectByName<Q3DSModelNode>(QLatin1String("FancySportsCar")); + \endcode + + Besides changing properties, adding or removing objects at runtime is also + possible. This will lead to the corresponding graphics objects appearing or + disappearing. For example, to spawn a new model object with the built-in + cube as its mesh: + + \badcode + Q3DSModelNode *cube = presentation->newObject<Q3DSModelNode>(QByteArrayLiteral("newCube")); + cube->setMesh(QLatin1String("#Cube")); + Q3DSDefaultMaterial *cubeMat = presentation->newObject<Q3DSDefaultMaterial>(QByteArrayLiteral("cubeMaterial")); + cube->appendChildNode(cubeMat); + group->appendChildNode(cube); + \endcode + + appendChildNode() takes ownership and inserts the given object in the + parent's child list. This is similar to QObject::setParent() but note that + QSGNode and Q3DSGraphObject are more powerful since they allow not just + appending but also inserting at arbitrary positions in the child list. + + When a newly created object gets added to a parent that itself is already + part of a hierarchy under a Q3DSScene, the object becomes active, which + triggers creating the graphics and 3D resources that are necessary to + render the object in the associated layer's texture. In the above example + this point is the last appendChildNode() call, assuming \c group is an + object already parented into a live Q3DSScene tree. + + To properly disconnect an object from the scene, use + Q3DSUipPresentation::unlinkObject(): + + \badcode + presentation->unlinkObject(cube); + delete cube; + \endcode + + Due to the unlinkObject() call, the cube will disappear from the screen. + Note that the Q3DSDefaultMaterial child object is unlinked and destroyed as + well, just like a child QObject is destroyed together with its parent. + + Being part of the scenegraph is not enough to get displayed, however. The + concept of slides has a great effect on visibility as well. To associate a + newly created object with a slide, call Q3DSSlide::addObject(). For + example, assuming the \c{.uip} file loaded has one slide under the master + slide: + + \badcode + Q3DSSlide *slide = static_cast<Q3DSSlide *>(presentation->masterSlide()->firstChild()); + slide->addObject(cubeMat); + slide->addObject(cube); + \endcode + + The children of the new object have to be managed manually here, hence the + separate addObject(cubeMat) call. It is not required that all descendants + of an object belong to the same slide as the object. + + When removing objects, make sure to disconnect them from the slide as well. + To do this recursively for all objects in the subtree that is about to + removed, one can do the following: + + \badcode + Q3DSUipPresentation::forAllObjectsInSubTree(cube, [slide](Q3DSGraphObject *obj) { + slide->removeObject(obj); + }); + \endcode + + There are many more possibilities with the Q3DSGraphObject API. Refer to + the header files for more insight. It is worth nothing that it is also + possible to build Qt 3D Studio scenes completely from C++, without using + any \c{.uip} files. Check the demo application under + \c{tests/manual/standalone} in the runtime's source tree for an example of + creating and managing interactive scenes this way. It is also a good + example for performing advanced tasks via the private API, like reacting on + input events, providing custom mesh data, and dynamically generating + texture maps. +*/ |