From 0e5983e737abcd664e07f22da342f1ae41b52124 Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Thu, 15 Nov 2018 15:00:09 +0100 Subject: Add a way to hook into the private API, with example and docs Change-Id: Ib46f4e753964eaad02f455f80962321fb64496c4 Reviewed-by: Andy Nichols --- examples/3dstudioruntime2/3dstudioruntime2.pro | 3 +- .../scenemanip/doc/images/scenemanip.png | Bin 0 -> 41349 bytes .../scenemanip/doc/src/scenemanip.qdoc | 46 ++++ examples/3dstudioruntime2/scenemanip/empty.uia | 15 ++ examples/3dstudioruntime2/scenemanip/main.cpp | 155 +++++++++++++ examples/3dstudioruntime2/scenemanip/main.qml | 74 ++++++ .../scenemanip/presentations/empty.uip | 31 +++ .../3dstudioruntime2/scenemanip/scenemanip.pro | 14 ++ .../3dstudioruntime2/scenemanip/scenemanip.qrc | 7 + src/runtime/api/q3dspresentation.cpp | 17 ++ src/runtime/api/q3dspresentation.h | 3 + src/runtime/api/q3dspresentation_p.h | 2 + src/runtime/doc/src/examples.qdoc | 1 + src/runtime/doc/src/index.qdoc | 1 + src/runtime/doc/src/scenecppapi.qdoc | 247 +++++++++++++++++++++ 15 files changed, 615 insertions(+), 1 deletion(-) create mode 100644 examples/3dstudioruntime2/scenemanip/doc/images/scenemanip.png create mode 100644 examples/3dstudioruntime2/scenemanip/doc/src/scenemanip.qdoc create mode 100644 examples/3dstudioruntime2/scenemanip/empty.uia create mode 100644 examples/3dstudioruntime2/scenemanip/main.cpp create mode 100644 examples/3dstudioruntime2/scenemanip/main.qml create mode 100644 examples/3dstudioruntime2/scenemanip/presentations/empty.uip create mode 100644 examples/3dstudioruntime2/scenemanip/scenemanip.pro create mode 100644 examples/3dstudioruntime2/scenemanip/scenemanip.qrc create mode 100644 src/runtime/doc/src/scenecppapi.qdoc 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 new file mode 100644 index 0000000..cdc5311 Binary files /dev/null and b/examples/3dstudioruntime2/scenemanip/doc/images/scenemanip.png differ 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 @@ + + + + + + + + + + + + + + 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 +#include +#include +#include +#include +#include + +#include +#include + +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(presentation->masterSlide()->firstChild()); + + Q3DSModelNode *prim = presentation->newObject(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(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(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 @@ + + + + + #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff + + + + + + + + + + + + + + + + + + + + + + + + + + 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 @@ + + + main.qml + empty.uia + presentations/empty.uip + + 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 > 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 + #include + \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 propertyNames() const; + QVector propertyValues() const; + + QVariant property(const char *name); + bool setProperty(const char *name, const QVariant &v); + QVector dynamicPropertyNames() const; + QVector 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(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(QByteArrayLiteral("newCube")); + cube->setMesh(QLatin1String("#Cube")); + Q3DSDefaultMaterial *cubeMat = presentation->newObject(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(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. +*/ -- cgit v1.2.3