diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-05-18 10:33:28 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-05-18 10:33:34 +0200 |
commit | 8bb3378d0d7c82eb1896ac043570ddab7c2edae9 (patch) | |
tree | f3fe8bce8b4df108c1cc9766fdbafea95c3bd490 | |
parent | 78ab305d5ca59a158232a8b47070ef35ae803033 (diff) | |
parent | 186e8bf9ec08b1aca289a23b93290bf4cd5521fe (diff) |
Merge remote-tracking branch 'origin/2.0'
Change-Id: Ic20a847cd27c284a3a1b51f142bda94f619ae51e
89 files changed, 3689 insertions, 480 deletions
diff --git a/examples/3dstudioruntime2/qmldatainput/doc/images/qmldatainput.png b/examples/3dstudioruntime2/qmldatainput/doc/images/qmldatainput.png Binary files differnew file mode 100644 index 0000000..e0567ee --- /dev/null +++ b/examples/3dstudioruntime2/qmldatainput/doc/images/qmldatainput.png diff --git a/examples/3dstudioruntime2/qmldatainput/doc/src/qmldatainput.qdoc b/examples/3dstudioruntime2/qmldatainput/doc/src/qmldatainput.qdoc new file mode 100644 index 0000000..58e6ae5 --- /dev/null +++ b/examples/3dstudioruntime2/qmldatainput/doc/src/qmldatainput.qdoc @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** 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 qmldatainput + \title Qt 3D Studio Runtime: QML DataInput Example + \ingroup qt3dstudioruntime2-examples-qml + \brief Demonstrates using DataInput elements in QML + + \image qmldatainput.png + + \e {This example demonstrates using DataInput elements with QML in Studio} + + \include examples-run.qdocinc + + \section1 Description + + The presentation consists of a static text element serving as a label and a rotating text + element for showing the input data as text. There is also a data input of type \e{Ranged Number} + in the presentation. This data input is used to control both the rotation animation time and + the text shown on the second text element. + The range is specified as [0 .. 360] in the presentation, where zero maps + to the beginning of the animation and 360 maps to the end of the animation. + + The \l {qmldatainput/qml/qmldatainput/main.qml}{qml main} loads the presentation and animates + a number property. The value of the animated property is bound to the + \l{DataInput::value}{value} property of the DataInput element, making the value show up in the + linked text element in the presentation. The same value is used to control the animation time: + + \snippet qmldatainput/qml/qmldatainput/main.qml 1 +*/ diff --git a/examples/3dstudioruntime2/qmldatainput/presentation/Paper05.png b/examples/3dstudioruntime2/qmldatainput/presentation/Paper05.png Binary files differnew file mode 100644 index 0000000..e70749d --- /dev/null +++ b/examples/3dstudioruntime2/qmldatainput/presentation/Paper05.png diff --git a/examples/3dstudioruntime2/qmldatainput/presentation/datainput.uip b/examples/3dstudioruntime2/qmldatainput/presentation/datainput.uip index 6b47e44..901e994 100644 --- a/examples/3dstudioruntime2/qmldatainput/presentation/datainput.uip +++ b/examples/3dstudioruntime2/qmldatainput/presentation/datainput.uip @@ -24,16 +24,21 @@ </Model> <Text id="Text3" /> <Text id="Text4" /> + <Model id="Rectangle" > + <Material id="Default_001" name="Default" > + <Image id="Default_001_diffusemap" /> + </Material> + </Model> </Layer> </Scene> </Graph> <Logic > <State name="Master Slide" component="#Scene" > - <Add ref="#Layer" multisampleaa="None" progressiveaa="4x" temporalaa="True" /> - <Add ref="#Camera" controlledproperty="$cameraRotInput rotation" pivot="0 0 0" rotation="0 0 0" /> - <Add ref="#Light" castshadow="True" controlledproperty="$colorInput lightdiffuse" lightdiffuse="1 0 0" position="-350.984 -229.258 -30" /> + <Add ref="#Layer" multisampleaa="SSAA" progressiveaa="8x" /> + <Add ref="#Camera" controlledproperty="$cameraRotInput rotation" pivot="0 0 0" position="0 0 -800" rotation="0 0 0" /> + <Add ref="#Light" castshadow="True" controlledproperty="$colorInput lightdiffuse" lightdiffuse="1 0 0" lighttype="Point" position="-300.444 70.829 -30" shdwfactor="11.89" shdwfilter="6.94" shdwmapres="11" /> <State id="Scene-Slide1" name="Slide1" initialplaystate="Pause" > - <Add ref="#Text" name="Text" font="TitilliumWeb-Regular" position="216.513 76.6172 -113.498" scale="1 1 1" size="24" textstring="0" > + <Add ref="#Text" name="Text" controlledproperty="$stringInput textstring" font="TitilliumWeb-Regular" position="216.513 76.6172 -113.498" scale="1 1 1" size="24" textstring="0" > <AnimationTrack property="rotation.x" type="EaseInOut" >0 0 0 0 10 0 0 0</AnimationTrack> <AnimationTrack property="rotation.y" type="EaseInOut" >0 0 0 0 10 0 0 0</AnimationTrack> <AnimationTrack property="rotation.z" type="EaseInOut" >0 0 0 0 10 -360 0 0</AnimationTrack> @@ -42,13 +47,16 @@ <Add ref="#Cone" name="Cone" controlledproperty="$scaleInput scale" position="-417.135 -225.166 0" sourcepath="#Cone" /> <Add ref="#Default" /> <Add ref="#Cylinder" name="Cylinder" controlledproperty="$variantInput opacity" position="131.347 -180.422 0" sourcepath="#Cylinder" /> - <Add ref="#Default_002" /> + <Add ref="#Default_002" diffuse="0.666667 1 0.498039" /> <Add ref="#Text6" name="Text6" font="TitilliumWeb-Regular" position="135.678 -300.019 -8.28656" size="16" textstring="Opacity control (Variant type)" /> <Add ref="#Text8" name="Text8" font="TitilliumWeb-Regular" position="-428.683 -290.118 0" size="16" textstring="Scale control" /> - <Add ref="#Cube2" name="Cube2" controlledproperty="$vec3Input rotation" position="409.919 -177.535 0" sourcepath="#Cube" /> + <Add ref="#Cube2" name="Cube2" controlledproperty="$cameraRotInput rotation" position="409.919 -177.535 0" sourcepath="#Cube" /> <Add ref="#Default_003" controlledproperty="$vec3Input2 diffuse" /> <Add ref="#Text3" name="Text3" font="TitilliumWeb-Regular" position="434.456 -304.552 0" size="16" textstring="Rotation control Diffuse color control" /> - <Add ref="#Text4" name="Text4" font="TitilliumWeb-Regular" position="-381.051 290.118 0" size="18" textstring="Directional light color and Camera xy rotation controlled via Datainput" /> + <Add ref="#Text4" name="Text4" font="TitilliumWeb-Regular" position="-381.051 290.118 0" size="18" textstring="Directional light color control Camera xy rotation control" /> + <Add ref="#Rectangle" name="Rectangle" position="0 -400 20" rotation="90.5 0 0" scale="11.0468 7.99191 9.12813" sourcepath="#Rectangle" /> + <Add ref="#Default_001" diffuse="0.623529 0.623529 0.623529" diffusemap="#Default_001_diffusemap" /> + <Add ref="#Default_001_diffusemap" sourcepath="Paper05.png" /> </State> </State> </Logic> diff --git a/examples/3dstudioruntime2/qmldatainput/qml/qmldatainput/main.qml b/examples/3dstudioruntime2/qmldatainput/qml/qmldatainput/main.qml index ef7d0e7..c0757e2 100644 --- a/examples/3dstudioruntime2/qmldatainput/qml/qmldatainput/main.qml +++ b/examples/3dstudioruntime2/qmldatainput/qml/qmldatainput/main.qml @@ -83,14 +83,14 @@ Item { property: "inputScaleVec3" duration: 12000 from: Qt.vector3d(0.3, 0.5, 0.5) - to: Qt.vector3d(1.0, 1.0, 1.0) + to: Qt.vector3d(4.0, 4.0, 1.0) loops: Animation.Infinite running: true } Vector3dAnimation { target: studio3D property: "inputColorVec3" - duration: 2000 + duration: 6000 from: Qt.vector3d(0.1, 0.1, 0.3) to: Qt.vector3d(1.0, 0.5, 1.0) loops: Animation.Infinite diff --git a/examples/3dstudioruntime2/qmldatainput/qmldatainput.qrc b/examples/3dstudioruntime2/qmldatainput/qmldatainput.qrc index 6fb7388..97aaeaa 100644 --- a/examples/3dstudioruntime2/qmldatainput/qmldatainput.qrc +++ b/examples/3dstudioruntime2/qmldatainput/qmldatainput.qrc @@ -3,5 +3,6 @@ <file>qml/qmldatainput/main.qml</file> <file>presentation/datainput.uia</file> <file>presentation/datainput.uip</file> + <file>presentation/Paper05.png</file> </qresource> </RCC> diff --git a/examples/3dstudioruntime2/simpleoffscreen/doc/images/simpleoffscreen.png b/examples/3dstudioruntime2/simpleoffscreen/doc/images/simpleoffscreen.png Binary files differnew file mode 100644 index 0000000..f406b3a --- /dev/null +++ b/examples/3dstudioruntime2/simpleoffscreen/doc/images/simpleoffscreen.png diff --git a/examples/3dstudioruntime2/simpleoffscreen/doc/src/simpleoffscreen.qdoc b/examples/3dstudioruntime2/simpleoffscreen/doc/src/simpleoffscreen.qdoc new file mode 100644 index 0000000..ecc0da8 --- /dev/null +++ b/examples/3dstudioruntime2/simpleoffscreen/doc/src/simpleoffscreen.qdoc @@ -0,0 +1,47 @@ +/**************************************************************************** +** +** 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 simpleoffscreen + \title Qt 3D Studio Runtime: Simple Offscreen Example + \ingroup qt3dstudioruntime2-examples-cpp + \brief Demonstrates using the Q3DSSurfaceViewer class render frames into image files + + \image simpleoffscreen.png + + \e {This example demonstrates offscreen usage of the Q3DSSurfaceViewer class} + + \include examples-run.qdocinc + + \section1 Description + + In this example there is no on-screen user interface. Instead, an + OpenGL framebuffer object is created. With the help of a + QOffscreenSurface the Qt 3D Studio presentation is rendered into + the OpenGL texture. The contents is then read back into a QImage + and saved into image files. +*/ diff --git a/examples/3dstudioruntime2/simpleqml/doc/images/simpleqml.png b/examples/3dstudioruntime2/simpleqml/doc/images/simpleqml.png Binary files differnew file mode 100644 index 0000000..a22b467 --- /dev/null +++ b/examples/3dstudioruntime2/simpleqml/doc/images/simpleqml.png diff --git a/examples/3dstudioruntime2/simpleqml/doc/src/simpleqml.qdoc b/examples/3dstudioruntime2/simpleqml/doc/src/simpleqml.qdoc new file mode 100644 index 0000000..dfd0f16 --- /dev/null +++ b/examples/3dstudioruntime2/simpleqml/doc/src/simpleqml.qdoc @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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 simpleqml + \title Qt 3D Studio Runtime: Simple QML Example + \ingroup qt3dstudioruntime2-examples-qml + \brief Demonstrates using the Studio3D element in a Qt Quick application + + \image simpleqml.png + + \e {This example demonstrates basic usage of the Studio3D element in Qt Quick applications} + + \include examples-run.qdocinc + + \section1 Description + + This example consists of a simple C++ main() function that sets up + a QQuickView and a QML scene demonstrating the usage of the \l + Studio3D, \l Presentation, \l DataInput, \l SceneElement, and \l + Element QML types. + + Besides displaying the presentation designed in the Qt 3D Studio + application, a few simple cases of interacting with the scene + (such as, changing 3D object properties via data input, changing + slides, controlling the timeline) are also demonstrated. +*/ diff --git a/examples/3dstudioruntime2/simpleqml/main.cpp b/examples/3dstudioruntime2/simpleqml/main.cpp index 897b59a..a0a3de3 100644 --- a/examples/3dstudioruntime2/simpleqml/main.cpp +++ b/examples/3dstudioruntime2/simpleqml/main.cpp @@ -56,6 +56,10 @@ int main(int argc, char *argv[]) { qputenv("QSG_INFO", "1"); QApplication app(argc, argv); + + // 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; diff --git a/examples/3dstudioruntime2/simpleqml/main.qml b/examples/3dstudioruntime2/simpleqml/main.qml index 4d47a47..0490a5a 100644 --- a/examples/3dstudioruntime2/simpleqml/main.qml +++ b/examples/3dstudioruntime2/simpleqml/main.qml @@ -98,33 +98,6 @@ Rectangle { id: barrelRef elementPath: "Barrel" // or Scene.Layer.Barrel but as long as it's unique the name's good enough } - - // Let's try out a QML subpresentation defined in-line, i.e. no separate .qml file. - SubPresentationSettings { - qmlStreams: [ - QmlStream { - presentationId: "embeddedQmlScene" - Rectangle { - color: "white" - Rectangle { - color: "red" - width: parent.width * 0.8 - height: parent.height * 0.8 - anchors.centerIn: parent - Text { - anchors.centerIn: parent - text: "Hello from\nembedded Qt Quick" - color: "white" - } - NumberAnimation on rotation { - from: 0; to: 360; duration: 10000 - loops: Animation.Infinite - } - } - } - } - ] - } } ignoredEvents: mouseEvCb.checked ? Studio3D.EnableAllEvents : (Studio3D.IgnoreMouseEvents | Studio3D.IgnoreWheelEvents) onRunningChanged: console.log("running: " + s3d.running) @@ -214,11 +187,6 @@ Rectangle { focusPolicy: Qt.NoFocus } Button { - text: "Fire event" - onClicked: s3dpres.fireEvent("Scene.Layer.Camera", "customCameraEvent") // in actionevent.uip this will change the sphere's color - focusPolicy: Qt.NoFocus - } - Button { text: "Toggle camera" onClicked: { var v = s3dpres.getAttribute("Scene.Layer.Camera", "eyeball") diff --git a/examples/3dstudioruntime2/simpleqml/presentation/barrel.uia b/examples/3dstudioruntime2/simpleqml/presentation/barrel.uia index 71d8e26..d936e42 100644 --- a/examples/3dstudioruntime2/simpleqml/presentation/barrel.uia +++ b/examples/3dstudioruntime2/simpleqml/presentation/barrel.uia @@ -3,7 +3,6 @@ <assets initial="barrel"> <dataInput name="di_text" type="String"/> <presentation id="barrel" src="barrel.uip"/> - <presentation-qml id="embeddedQmlScene" args="dummy"/> </assets> <statemachine ref="#logic"> <visual-states> diff --git a/examples/3dstudioruntime2/simpleqml/presentation/barrel.uip b/examples/3dstudioruntime2/simpleqml/presentation/barrel.uip index 66b40c2..9299f39 100644 --- a/examples/3dstudioruntime2/simpleqml/presentation/barrel.uip +++ b/examples/3dstudioruntime2/simpleqml/presentation/barrel.uip @@ -6,7 +6,6 @@ </ProjectSettings> <Graph > <Scene id="Scene" > - <Layer id="splayer" /> <Layer id="Layer" > <Camera id="Camera" /> <Light id="Light" /> @@ -25,10 +24,10 @@ </Graph> <Logic > <State name="Master Slide" component="#Scene" > + <Add ref="#Layer" /> <Add ref="#Camera" /> <Add ref="#Light" /> <State id="Scene-Slide1" name="Slide1" playmode="Looping" > - <Add ref="#splayer" name="splayer" height="30" sourcepath="embeddedQmlScene" top="50" width="30" /> <Add ref="#Barrel" name="Barrel" position="0 -42 -483" rotation="90 0 0" scale="100 100 100" sourcepath=".\barrel\meshes\Barrel.mesh#1" > <AnimationTrack property="opacity" type="EaseInOut" /> <AnimationTrack property="rotation.x" type="EaseInOut" >0 90 100 100 5 64 100 100 10 90 100 100</AnimationTrack> diff --git a/examples/3dstudioruntime2/simplewidget/doc/images/simplewidget.png b/examples/3dstudioruntime2/simplewidget/doc/images/simplewidget.png Binary files differnew file mode 100644 index 0000000..a975c73 --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/doc/images/simplewidget.png diff --git a/examples/3dstudioruntime2/simplewidget/doc/src/simplewidget.qdoc b/examples/3dstudioruntime2/simplewidget/doc/src/simplewidget.qdoc new file mode 100644 index 0000000..ab02d59 --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/doc/src/simplewidget.qdoc @@ -0,0 +1,48 @@ +/**************************************************************************** +** +** 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 simplewidget + \title Qt 3D Studio Runtime: Simple Widget Example + \ingroup qt3dstudioruntime2-examples-cpp + \brief Demonstrates using the Q3DSWidget widget in a Qt C++ application + + \image simplewidget.png + + \e {This example demonstrates basic usage of the Q3DSWidget class} + + \include examples-run.qdocinc + + \section1 Description + + This example consists of a simple widget UI that includes a + Q3DSWidget. This QOpenGLWidget subclass displays and controls Qt + 3D Studio presentations. Changing the value of a text node via + data input, basic error handling, and the means of reloading or + opening presentations, as well as toggling the in-scene profiling + pane are also demonstrated. +*/ diff --git a/examples/3dstudioruntime2/simplewidget/main.cpp b/examples/3dstudioruntime2/simplewidget/main.cpp index 50b3fac..6d02374 100644 --- a/examples/3dstudioruntime2/simplewidget/main.cpp +++ b/examples/3dstudioruntime2/simplewidget/main.cpp @@ -59,7 +59,6 @@ #include <q3dsruntimeglobal.h> #include <Q3DSWidget> #include <Q3DSPresentation> -#include <Q3DSDataInput> int main(int argc, char *argv[]) { @@ -81,17 +80,8 @@ int main(int argc, char *argv[]) QMessageBox::critical(&w, QLatin1String("Failed to load presentation"), msg, QLatin1String("Ok")); }); - // The presentation has a data input entry "di_text" for the textstring - // property of one of the Text nodes. Provide a custom value. Do this in a - // manner so that the value is set even when doing a Reload or changing the - // presentation object's source. - Q3DSDataInput dataInput(w3DS->presentation(), QLatin1String("di_text")); - QObject::connect(w3DS, &Q3DSWidget::presentationLoaded, w3DS, [&dataInput] { - dataInput.setValue(QLatin1String("Hello world")); - }); - w3DS->presentation()->setProfilingEnabled(true); - w3DS->presentation()->setSource(QUrl(QLatin1String("qrc:/barrel.uip"))); + w3DS->presentation()->setSource(QUrl(QLatin1String("qrc:/presentation/SampleProject.uia"))); layout->addWidget(w3DS); QPushButton *openBtn = new QPushButton(QLatin1String("Open")); diff --git a/examples/3dstudioruntime2/simplewidget/presentation/SampleProject.uia b/examples/3dstudioruntime2/simplewidget/presentation/SampleProject.uia new file mode 100644 index 0000000..d59165e --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/presentation/SampleProject.uia @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8"?> +<application xmlns="http://qt.io/qt3dstudio/uia"> + <assets initial="SampleProject"> + <presentation id="SampleProject" src="SampleProject.uip"/> + </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/simplewidget/presentation/SampleProject.uip b/examples/3dstudioruntime2/simplewidget/presentation/SampleProject.uip new file mode 100644 index 0000000..4c1325e --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/presentation/SampleProject.uip @@ -0,0 +1,77 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<UIP version="3" > + <Project > + <ProjectSettings author="" company="" presentationWidth="800" presentationHeight="800" maintainAspect="True" > + <CustomColors count="16" >#ff5500 #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff #ffffff</CustomColors> + </ProjectSettings> + <Classes > + <CustomMaterial id="simple_glass" name="simple_glass" sourcepath="materials/simple_glass.material" /> + </Classes> + <Graph > + <Scene id="Scene" > + <Layer id="Layer2" > + <Camera id="Camera_001" /> + <Light id="Light_001" /> + <Model id="NeedleSpeed_001" name="NeedleSpeed" importid="NeedleSpeed" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="models/Speedometer/meshes/NeedleSpeed.mesh" > + <Material id="NeedleBlack_002" name="NeedleBlack" blendmode="Normal" diffuse="0 0 0" emissivepower="0" importid="NeedleBlack" opacity="100" specularamount="0" specularroughness="9.41177" /> + <Material id="NeedleWhite_002" /> + </Model> + </Layer> + <Layer id="Layer" > + <Camera id="Camera" /> + <Light id="Light" /> + <Group id="Speedometer" importid="__import__root__" > + <Group id="Group_Speedometer_Master" name="Group_Speedometer_Master" importid="Group_Speedometer_Master" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" > + <Model id="Speedometer_001" name="Speedometer" importid="Speedometer" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="models/Speedometer/meshes/Speedometer.mesh" > + <CustomMaterial id="BaseMetal" class="#simple_glass" /> + <ReferencedMaterial id="HighLight" /> + <Material id="NeedleWhite_001" name="NeedleWhite" blendmode="Normal" diffuse="0.8 0.8 0.8" emissivepower="0" importid="NeedleWhite_0005" opacity="100" specularamount="0" specularroughness="27.451" /> + <Material id="BlackMetalRing" name="BlackMetalRing" blendmode="Normal" diffuse="0.0578313 0.0578313 0.0578313" emissivepower="0" importid="BlackMetalRing" opacity="100" specularamount="0" specularroughness="99.8039" /> + <Material id="NeedleBlack_001" name="NeedleBlack" blendmode="Normal" diffuse="0 0 0" emissivepower="0" importid="NeedleBlack_0006" opacity="100" specularamount="0" specularroughness="9.41177" /> + <Material id="SpeedometerBg" name="SpeedometerBg" blendmode="Normal" diffuse="1 1 1" diffusemap="#SpeedometerBg_diffusemap" emissivepower="0" importid="SpeedometerBg" opacity="100" specularamount="0" specularroughness="9.41177" > + <Image id="SpeedometerBg_diffusemap" name="SpeedometerBg_diffusemap" importid="SpeedometerBg_diffusemap" sourcepath="models/Speedometer/maps/Speed.png" /> + </Material> + </Model> + </Group> + </Group> + </Layer> + </Scene> + </Graph> + <Logic > + <State name="Master Slide" component="#Scene" > + <Add ref="#Layer" multisampleaa="SSAA" probebright="500" /> + <Add ref="#Camera" fov="30" position="0 0 -400" /> + <Add ref="#Light" brightness="200" lightdiffuse="1 1 1" lightspecular="0 0.666667 1" lighttype="Point" pivot="100 0 0" position="0 0 -50" > + <AnimationTrack property="rotation.x" type="EaseInOut" >0 0 100 100 5 0 100 100</AnimationTrack> + <AnimationTrack property="rotation.y" type="EaseInOut" >0 0 100 100 5 0 100 100</AnimationTrack> + <AnimationTrack property="rotation.z" type="EaseInOut" >0 45 100 100 5 -225 100 100</AnimationTrack> + </Add> + <State id="Scene-Slide1" name="Slide1" playmode="PingPong" playthroughto="Next" > + <Set ref="#Layer" endtime="5000" /> + <Set ref="#Camera" endtime="5000" /> + <Set ref="#Light" endtime="5000" /> + <Add ref="#Layer2" name="Layer2" endtime="5000" multisampleaa="None" progressiveaa="8x" /> + <Add ref="#Camera_001" endtime="5000" fov="30" position="0 0 -600" /> + <Add ref="#Light_001" endtime="5000" /> + <Add ref="#NeedleSpeed_001" name="NeedleSpeed" endtime="5000" importfile="models/Speedometer/Speedometer.import" pivot="5 5 0" > + <AnimationTrack property="rotation.x" type="EaseInOut" >0 0 100 100 2.13 0 0 0 5 0 100 100</AnimationTrack> + <AnimationTrack property="rotation.y" type="EaseInOut" >0 0 100 100 2.13 0 0 0 5 0 100 100</AnimationTrack> + <AnimationTrack property="rotation.z" type="EaseInOut" >0 0 100 100 2.13 -105.249 0 0 5 -270 100 100</AnimationTrack> + </Add> + <Add ref="#NeedleBlack_002" diffuse="0 0.333333 1" importfile="models/Speedometer/Speedometer.import" /> + <Add ref="#NeedleWhite_002" name="NeedleWhite" diffuse="1 1 1" specularamount="0" /> + <Add ref="#Speedometer" name="Speedometer" endtime="5000" importfile="models/Speedometer/Speedometer.import" position="0 0 0" scale="0.7 0.7 0.7" sourcepath="models/Speedometer/Speedometer.import" /> + <Add ref="#Group_Speedometer_Master" endtime="5000" importfile="models/Speedometer/Speedometer.import" /> + <Add ref="#Speedometer_001" endtime="5000" importfile="models/Speedometer/Speedometer.import" /> + <Add ref="#BaseMetal" name="BaseMetal" glass_color="0 0.333333 1" /> + <Add ref="#HighLight" name="HighLight" endtime="5000" referencedmaterial="#BaseMetal" /> + <Add ref="#NeedleWhite_001" importfile="models/Speedometer/Speedometer.import" /> + <Add ref="#BlackMetalRing" diffuse="0 0.0862745 0.596078" importfile="models/Speedometer/Speedometer.import" specularamount="0" /> + <Add ref="#NeedleBlack_001" importfile="models/Speedometer/Speedometer.import" /> + <Add ref="#SpeedometerBg" diffuse="0.270588 0.501961 1" importfile="models/Speedometer/Speedometer.import" specularamount="0.1" specularroughness="1" speculartint="0.529412 0.772549 1" /> + <Add ref="#SpeedometerBg_diffusemap" importfile="models/Speedometer/Speedometer.import" /> + </State> + </State> + </Logic> + </Project> +</UIP> diff --git a/examples/3dstudioruntime2/simplewidget/presentation/maps/materials/shadow.png b/examples/3dstudioruntime2/simplewidget/presentation/maps/materials/shadow.png Binary files differnew file mode 100644 index 0000000..599b1cc --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/presentation/maps/materials/shadow.png diff --git a/examples/3dstudioruntime2/simplewidget/presentation/maps/materials/spherical_checker.png b/examples/3dstudioruntime2/simplewidget/presentation/maps/materials/spherical_checker.png Binary files differnew file mode 100644 index 0000000..e42394d --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/presentation/maps/materials/spherical_checker.png diff --git a/examples/3dstudioruntime2/simplewidget/presentation/materials/simple_glass.material b/examples/3dstudioruntime2/simplewidget/presentation/materials/simple_glass.material new file mode 100644 index 0000000..a6b4ee0 --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/presentation/materials/simple_glass.material @@ -0,0 +1,197 @@ +<Material name="simple_glass" version="1.0"> + <MetaData > + <Property formalName="Environment Map" name="uEnvironmentTexture" description="Environment texture for the material" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="environment" default="./maps/materials/spherical_checker.png" category="Material"/> + <Property formalName="Enable Environment" name="uEnvironmentMappingEnabled" description="Enable environment mapping" type="Boolean" default="True" category="Material"/> + <Property formalName="Baked Shadow Map" name="uBakedShadowTexture" description="Baked shadow texture for the material" type="Texture" filter="linear" minfilter="linearMipmapLinear" clamp="repeat" usage="shadow" default="./maps/materials/shadow.png" category="Material"/> + <Property formalName="Enable Shadow Mapping" name="uShadowMappingEnabled" description="Enable shadow mapping" type="Boolean" default="False" category="Material"/> + <Property formalName="Fresnel Power" name="uFresnelPower" description="Fresnel power of the material" type="Float" default="1.0" category="Material"/> + <Property formalName="Minimum Opacity" name="uMinOpacity" description="Minimum opacity of the material" type="Float" default="0.5" category="Material"/> + <Property formalName="Reflectivity" name="reflectivity_amount" type="Float" min="0.000000" max="1.000000" default="1.000000" description="Reflectivity factor" category="Material"/> + <Property formalName="Glass ior" name="glass_ior" hidden="True" type="Float" default="1.100000" description="Index of refraction of the material" category="Material"/> + <Property formalName="Glass Color" name="glass_color" type="Color" default="0.9 0.9 0.9" description="Color of the material" category="Material"/> + </MetaData> + <Shaders type="GLSL" version="330"> + <Shader> + <Shared> </Shared> +<VertexShader> + </VertexShader> + <FragmentShader> + +// add enum defines +#define scatter_reflect 0 +#define scatter_transmit 1 +#define scatter_reflect_transmit 2 + +#define QT3DS_ENABLE_UV0 1 +#define QT3DS_ENABLE_WORLD_POSITION 1 +#define QT3DS_ENABLE_TEXTAN 1 +#define QT3DS_ENABLE_BINORMAL 0 + +#include "vertexFragmentBase.glsllib" + +// set shader output +out vec4 fragColor; + +// add structure defines +struct layer_result +{ + vec4 base; + vec4 layer; + mat3 tanFrame; +}; + + +// temporary declarations +vec3 ftmp0; + vec4 tmpShadowTerm; + +layer_result layers[1]; + +#include "SSAOCustomMaterial.glsllib" +#include "sampleLight.glsllib" +#include "sampleProbe.glsllib" +#include "sampleArea.glsllib" +#include "square.glsllib" +#include "calculateRoughness.glsllib" +#include "evalBakedShadowMap.glsllib" +#include "evalEnvironmentMap.glsllib" +#include "luminance.glsllib" +#include "microfacetBSDF.glsllib" +#include "physGlossyBSDF.glsllib" +#include "simpleGlossyBSDF.glsllib" +#include "abbeNumberIOR.glsllib" +#include "fresnelLayer.glsllib" +#include "refraction.glsllib" + +bool evalTwoSided() +{ + return( true ); +} + +vec3 computeFrontMaterialEmissive() +{ + return( vec3( 0, 0, 0 ) ); +} + +void computeFrontLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor ) +{ +#if QT3DS_ENABLE_CG_LIGHTING + layers[0].base += tmpShadowTerm * microfacetBSDF( layers[0].tanFrame, lightDir, viewDir, lightSpecular, materialIOR, 0.000000, 0.000000, scatter_reflect_transmit ); + +#endif +} + +void computeFrontAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular ) +{ +#if QT3DS_ENABLE_CG_LIGHTING + layers[0].base += tmpShadowTerm * lightSpecular * sampleAreaGlossy( layers[0].tanFrame, varWorldPos, lightIdx, viewDir, 0.000000, 0.000000 ); + +#endif +} + +void computeFrontLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor ) +{ +#if !QT3DS_ENABLE_LIGHT_PROBE + layers[0].base += tmpShadowTerm * microfacetSampledBSDF( layers[0].tanFrame, viewDir, 0.000000, 0.000000, scatter_reflect_transmit ); + +#else + layers[0].base += tmpShadowTerm * sampleGlossyAniso( layers[0].tanFrame, viewDir, 0.000000, 0.000000 ); + +#endif +} + +vec3 computeBackMaterialEmissive() +{ + return( vec3(0, 0, 0) ); +} + +void computeBackLayerColor( in vec3 normal, in vec3 lightDir, in vec3 viewDir, in vec3 lightDiffuse, in vec3 lightSpecular, in float materialIOR, float aoFactor ) +{ +#if QT3DS_ENABLE_CG_LIGHTING + layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 ); + layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 ); +#endif +} + +void computeBackAreaColor( in int lightIdx, in vec4 lightDiffuse, in vec4 lightSpecular ) +{ +#if QT3DS_ENABLE_CG_LIGHTING + layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 ); + layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 ); +#endif +} + +void computeBackLayerEnvironment( in vec3 normal, in vec3 viewDir, float aoFactor ) +{ +#if !QT3DS_ENABLE_LIGHT_PROBE + layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 ); + layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 ); +#else + layers[0].base += vec4( 0.0, 0.0, 0.0, 1.0 ); + layers[0].layer += vec4( 0.0, 0.0, 0.0, 1.0 ); +#endif +} + +float computeIOR() +{ + return( true ? 1.0 : luminance( vec3( abbeNumberIOR(glass_ior, 0.000000 ) ) ) ); +} + +float evalCutout() +{ + return( 1.000000 ); +} + +vec3 computeNormal() +{ + return( normal ); +} + +void computeTemporaries() +{ + ftmp0 = vec3( reflectivity_amount ); + tmpShadowTerm = evalBakedShadowMap( texCoord0 ); +} + +vec4 computeLayerWeights( in float alpha ) +{ + vec4 color; + color = layers[0].base * vec4( ftmp0, 1.0); + return color; +} + + +void initializeLayerVariables(void) +{ + // clear layers + layers[0].base = vec4(0.0, 0.0, 0.0, 1.0); + layers[0].layer = vec4(0.0, 0.0, 0.0, 1.0); + layers[0].tanFrame = orthoNormalize( tangentFrame( normal, varWorldPos ) ); +} + +vec4 computeGlass(in vec3 normal, in float materialIOR, in float alpha, in vec4 color) +{ + vec4 rgba = color; + float ratio = simpleFresnel( normal, materialIOR, uFresnelPower ); + vec3 absorb_color = ( log( glass_color )/-1.000000 ); + // prevent log(0) -> inf number issue + if ( isinf(absorb_color.r) ) absorb_color.r = 1.0; + if ( isinf(absorb_color.g) ) absorb_color.g = 1.0; + if ( isinf(absorb_color.b) ) absorb_color.b = 1.0; + rgba.rgb = mix(vec3(1.0) - absorb_color, rgba.rgb * (vec3(1.0) - absorb_color), ratio); + rgba.a = mix(uMinOpacity, alpha, ratio); + return rgba; +} + + </FragmentShader> + </Shader> + </Shaders> +<Passes > + <ShaderKey value="36"/> + <LayerKey count="1"/> + <Pass > + <Blending source="SrcAlpha" dest="OneMinusSrcAlpha"/> + <RenderState name="CullFace"/> + </Pass> +</Passes> +</Material> diff --git a/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/Speedometer.import b/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/Speedometer.import new file mode 100644 index 0000000..d74ef62 --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/Speedometer.import @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="UTF-8" ?> +<UIP Version="1" > + <Project Revision="1" > + <Graph > + <Group id="__import__root__" > + <Group id="Group_Speedometer_Master" name="Group_Speedometer_Master" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" > + <Model id="NeedleSpeed" name="NeedleSpeed" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes/NeedleSpeed.mesh" > + <Material id="NeedleBlack" name="NeedleBlack" blendmode="Normal" diffuse="0 0 0" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.41177" /> + <Material id="NeedleWhite" name="NeedleWhite" blendmode="Normal" diffuse="0.8 0.8 0.8" emissivepower="0" opacity="100" specularamount="0" specularroughness="27.451" /> + </Model> + <Model id="Speedometer" name="Speedometer" orientation="Right Handed" position="0 0 -0" rotation="0 -0 0" rotationorder="XYZr" scale="1 1 1" sourcepath="meshes/Speedometer.mesh" > + <Material id="BaseMetal" name="BaseMetal" blendmode="Normal" diffuse="0.01728 0.01728 0.01728" emissivepower="0" opacity="100" specularamount="0" specularroughness="11.3725" /> + <Material id="HighLight" name="HighLight" blendmode="Normal" diffuse="0.298 0.54088 0.8" emissivepower="0" opacity="66.8675" specularamount="0" specularroughness="100" /> + <Material id="NeedleWhite_0005" name="NeedleWhite" blendmode="Normal" diffuse="0.8 0.8 0.8" emissivepower="0" opacity="100" specularamount="0" specularroughness="27.451" /> + <Material id="BlackMetalRing" name="BlackMetalRing" blendmode="Normal" diffuse="0.0578313 0.0578313 0.0578313" emissivepower="0" opacity="100" specularamount="0" specularroughness="99.8039" /> + <Material id="NeedleBlack_0006" name="NeedleBlack" blendmode="Normal" diffuse="0 0 0" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.41177" /> + <Material id="SpeedometerBg" name="SpeedometerBg" blendmode="Normal" diffuse="1 1 1" diffusemap="SpeedometerBg_diffusemap" emissivepower="0" opacity="100" specularamount="0" specularroughness="9.41177" > + <Image id="SpeedometerBg_diffusemap" name="SpeedometerBg_diffusemap" sourcepath="maps/Speed.png" /> + </Material> + </Model> + </Group> + </Group> + </Graph> + <Import SrcFile="" ImageDir="Images" MeshDir="Meshes" > + <Image > + <Source >Speed.png</Source> + <Dest >maps/Speed.png</Dest> + </Image> + <Mesh > + <Source >Speedometer</Source> + <Dest >meshes/Speedometer.mesh</Dest> + </Mesh> + <Mesh > + <Source >NeedleSpeed</Source> + <Dest >meshes/NeedleSpeed.mesh</Dest> + </Mesh> + </Import> + </Project> +</UIP> diff --git a/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/maps/Speed.png b/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/maps/Speed.png Binary files differnew file mode 100644 index 0000000..84b7e4d --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/maps/Speed.png diff --git a/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/meshes/NeedleSpeed.mesh b/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/meshes/NeedleSpeed.mesh Binary files differnew file mode 100644 index 0000000..72220cd --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/meshes/NeedleSpeed.mesh diff --git a/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/meshes/Speedometer.mesh b/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/meshes/Speedometer.mesh Binary files differnew file mode 100644 index 0000000..9f7ba34 --- /dev/null +++ b/examples/3dstudioruntime2/simplewidget/presentation/models/Speedometer/meshes/Speedometer.mesh diff --git a/examples/3dstudioruntime2/simplewidget/simplewidget.qrc b/examples/3dstudioruntime2/simplewidget/simplewidget.qrc index e9b7006..3f6f2fa 100644 --- a/examples/3dstudioruntime2/simplewidget/simplewidget.qrc +++ b/examples/3dstudioruntime2/simplewidget/simplewidget.qrc @@ -1,12 +1,12 @@ <RCC> <qresource prefix="/"> - <file alias="barrel.uia">../simpleqml/presentation/barrel.uia</file> - <file alias="barrel.uip">../simpleqml/presentation/barrel.uip</file> - <file alias="barrel/meshes/Barrel.mesh">../simpleqml/presentation/barrel/meshes/Barrel.mesh</file> - <file alias="fonts/Arimo-Regular.ttf">../simpleqml/presentation/fonts/Arimo-Regular.ttf</file> - <file alias="maps/barrel_barrel_Diffuse.png">../simpleqml/presentation/maps/barrel_barrel_Diffuse.png</file> - <file alias="maps/barrel_barrel_Emissive.png">../simpleqml/presentation/maps/barrel_barrel_Emissive.png</file> - <file alias="maps/barrel_barrel_Normal.png">../simpleqml/presentation/maps/barrel_barrel_Normal.png</file> - <file alias="maps/barrel_barrel_Specular.png">../simpleqml/presentation/maps/barrel_barrel_Specular.png</file> + <file>presentation/SampleProject.uia</file> + <file>presentation/SampleProject.uip</file> + <file>presentation/maps/materials/spherical_checker.png</file> + <file>presentation/maps/materials/shadow.png</file> + <file>presentation/materials/simple_glass.material</file> + <file>presentation/models/Speedometer/maps/Speed.png</file> + <file>presentation/models/Speedometer/meshes/Speedometer.mesh</file> + <file>presentation/models/Speedometer/meshes/NeedleSpeed.mesh</file> </qresource> </RCC> diff --git a/examples/3dstudioruntime2/simplewindow/doc/images/simplewindow.png b/examples/3dstudioruntime2/simplewindow/doc/images/simplewindow.png Binary files differnew file mode 100644 index 0000000..37550c7 --- /dev/null +++ b/examples/3dstudioruntime2/simplewindow/doc/images/simplewindow.png diff --git a/examples/3dstudioruntime2/simplewindow/doc/src/simplewindow.qdoc b/examples/3dstudioruntime2/simplewindow/doc/src/simplewindow.qdoc new file mode 100644 index 0000000..b00bc3e --- /dev/null +++ b/examples/3dstudioruntime2/simplewindow/doc/src/simplewindow.qdoc @@ -0,0 +1,51 @@ +/**************************************************************************** +** +** 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 simplewindow + \title Qt 3D Studio Runtime: Simple Window Example + \ingroup qt3dstudioruntime2-examples-cpp + \brief Demonstrates using the Q3DSSurfaceViewer class in order to render in a QWindow + + \image simplewindow.png + + \e {This example demonstrates basic usage of the Q3DSSurfaceViewer class} + + \include examples-run.qdocinc + + \section1 Description + + This example consists of an OpenGL-based QWindow. The contents is + provided by a Q3DSSurfaceViewer instance by loading up a simple Qt + 3D Studio presentation. + + When targeting a QWindow, the application can choose whether it + wants to be in control of updates (i.e. manually requesting the + next frame by calling Q3DSSurfaceViewer::update()). By passing + the \c{--multi} command-line argument the example demonstrates + both types of usages. +*/ diff --git a/examples/3dstudioruntime2/simplewindow/main.cpp b/examples/3dstudioruntime2/simplewindow/main.cpp index 15796b4..3fea28b 100644 --- a/examples/3dstudioruntime2/simplewindow/main.cpp +++ b/examples/3dstudioruntime2/simplewindow/main.cpp @@ -80,13 +80,13 @@ int main(int argc, char *argv[]) }); // The presentation has a data input entry "di_text" for the textstring - // property of one of the Text nodes. Provide a custom value. + // property of one of the Text nodes. Provide a custom value. Do this in a + // manner so that the value is set even when doing a Reload or changing the + // presentation object's source. Q3DSDataInput dataInput(viewer.presentation(), QLatin1String("di_text")); - // Assuming the source is never changed or reloaded, a plain setValue() - // call is good enough. Otherwise, we would need to connect to the - // presentationLoaded() signal and set the value whenever a new - // presentation is loaded. - dataInput.setValue(QLatin1String("Hello world")); + QObject::connect(&viewer, &Q3DSSurfaceViewer::presentationLoaded, &viewer, [&dataInput] { + dataInput.setValue(QLatin1String("Hello world")); + }); viewer.presentation()->setSource(QUrl(QLatin1String("qrc:/barrel.uip"))); viewer.create(&w, w.context()); diff --git a/src/doc/doc.pro b/src/doc/doc.pro deleted file mode 100644 index eba9ea3..0000000 --- a/src/doc/doc.pro +++ /dev/null @@ -1,8 +0,0 @@ -TEMPLATE = aux - -build_online_docs: \ - QMAKE_DOCS = $$PWD/online/Qt3DStudioRuntime2.qdocconf -else: \ - QMAKE_DOCS = $$PWD/Qt3DStudioRuntime2.qdocconf - -OTHER_FILES += $$PWD/src/*.qdoc diff --git a/src/doc/qt3d-runtime-project.qdocconf b/src/doc/qt3d-runtime-project.qdocconf deleted file mode 100644 index 1c69bf4..0000000 --- a/src/doc/qt3d-runtime-project.qdocconf +++ /dev/null @@ -1,55 +0,0 @@ -project = Qt3DStudioRuntime2 -description = Qt 3D Studio Runtime Reference Manual -version = $QT_VERSION - -sourcedirs += ./src -imagedirs += ./src/images - -sourcedirs += ../runtime/api -headerdirs += ../runtime/api - -sourcedirs += ../imports/studio3d -headerdirs += ../imports/studio3d - -depends = qtcore qtgui qtwidgets qtqml qtquick qtdoc qt3dcore qt3drender qt3dlogic qt3danimation - -qhp.projects = 3dstudioruntime2 - -qhp.3dstudioruntime2.file = Qt3DStudioRuntime2.qhp -qhp.3dstudioruntime2.namespace = io.qt.qt3dstudioruntime2.$QT_VERSION_TAG -qhp.3dstudioruntime2.virtualFolder = Qt3DStudioRuntime2 -qhp.3dstudioruntime2.indexTitle = Qt 3D Studio Runtime -qhp.3dstudioruntime2.indexRoot = - -qhp.3dstudioruntime2.filterAttributes = Qt3DStudioRuntime2 $QT_VERSION -qhp.3dstudioruntime2.customFilters.Qt.name = Qt3DStudioRuntime2 $QT_VERSION -qhp.3dstudioruntime2.customFilters.Qt.filterAttributes = Qt3DStudioRuntime2 $QT_VERSION - -qhp.3dstudioruntime2.subprojects = manual qmltypes classes - -qhp.3dstudioruntime2.subprojects.manual.title = Qt 3D Studio Runtime -qhp.3dstudioruntime2.subprojects.manual.indexTitle = Qt 3D Studio Runtime TOC -qhp.3dstudioruntime2.subprojects.manual.type = manual - -qhp.3dstudioruntime2.subprojects.qmltypes.title = QML Types -qhp.3dstudioruntime2.subprojects.qmltypes.indexTitle = Qt 3D Studio Runtime QML Types -qhp.3dstudioruntime2.subprojects.qmltypes.selectors = qmltype -qhp.3dstudioruntime2.subprojects.qmltypes.sortPages = true - -qhp.3dstudioruntime2.subprojects.classes.title = C++ Classes -qhp.3dstudioruntime2.subprojects.classes.indexTitle = Qt 3D Studio Runtime C++ Classes -qhp.3dstudioruntime2.subprojects.classes.selectors = class fake:headerfile -qhp.3dstudioruntime2.subprojects.classes.sortPages = true - -# Add an .html file with sidebar content, used in the online style -HTML.stylesheets += style/qt5-sidebar.html - -navigation.homepage = Qt 3D Studio Runtime -navigation.cppclassespage = Qt 3D Studio Runtime C++ Classes -navigation.qmltypespage = Qt 3D Studio Runtime QML Types -buildversion = "Qt 3D Studio Runtime $QT_VER Manual" - -examplesinstallpath = 3dstudioruntime2 -exampledirs += ../../examples/3dstudioruntime2 - -Cpp.ignoretokens += Q3DSV_EXPORT diff --git a/src/doc/style/qt5-sidebar.html b/src/doc/style/qt5-sidebar.html deleted file mode 100644 index 89b8c0d..0000000 --- a/src/doc/style/qt5-sidebar.html +++ /dev/null @@ -1,13 +0,0 @@ -<div class="sectionlist normallist"> - <div class="heading"> - <a name="reference"></a> - <h2 id="reference">Qt 3D Studio Runtime</h2> - </div> - <div class="indexboxcont indexboxbar"> - <ul> - <li><a href="getting-started.html">Getting Started</a></li> - <li><a href="qt3dstudio-studio.html">Studio</a></li> - <li><a href="qtstudio3d-qml-examples.html">Examples</a></li> - <li><a href="copyright-notices.html">Copyright Notices</a></li> - </ul> - </div> diff --git a/src/imports/studio3d/q3dsstudio3ditem.cpp b/src/imports/studio3d/q3dsstudio3ditem.cpp index 2326d1f..b585122 100644 --- a/src/imports/studio3d/q3dsstudio3ditem.cpp +++ b/src/imports/studio3d/q3dsstudio3ditem.cpp @@ -58,9 +58,67 @@ QT_BEGIN_NAMESPACE \inqmlmodule QtStudio3D \ingroup 3dstudioruntime2 \inherits Item - \brief blah - blah + \brief Qt 3D Studio presentation viewer. + + This type enables developers to embed Qt 3D Studio presentations in Qt + Quick. + + \section2 Example usage + + \qml + Studio3D { + id: studio3D + Presentation { + source: "qrc:///presentation.uia" + SceneElement { + id: scene + elementPath: "Scene" + currentSlideIndex: 2 + } + Element { + id: textLabel + elementPath: "Scene.Layer.myLabel" + } + } + ViewerSettings { + showRenderStats: true + } + onRunningChanged: { + console.log("Presentation ready!"); + } + } + \endqml +*/ + +/*! + \qmlsignal Studio3D::frameUpdate() + + This signal is emitted each time a frame has been updated regardless of + visibility. This allows a hidden Studio3D element to still process + information every frame, even though the renderer is not rendering. + + The corresponding handler is \c onFrameUpdate. + + To prevent expensive handlers from being processed when hidden, add an + early return to the top like: + + \qml + onFrameUpdate: { + if (!visible) return; + ... + } + \endqml +*/ + +/*! + \qmlsignal Studio3D::presentationReady() + + This signal is emitted when the viewer has been initialized and the + presentation is ready to be shown. The difference to \c running property is + that the viewer has to be visible for \c running to get \c{true}. This + signal is useful for displaying splash screen while viewer is getting + initialized. */ static bool engineCleanerRegistered = false; @@ -94,11 +152,30 @@ Q3DSStudio3DItem::~Q3DSStudio3DItem() { } +/*! + \qmlproperty Presentation Studio3D::presentation + + Accessor for the presentation. Applications are expected to create a single + Presentation child object for Studio3D. If this is omitted, a presentation + is created automatically. + + This property is read-only. +*/ + Q3DSPresentationItem *Q3DSStudio3DItem::presentation() const { return m_presentation; } +/*! + \qmlproperty bool Studio3D::running + + The value of this property is \c true when the viewer has been initialized + and the presentation is running. + + This property is read-only. +*/ + bool Q3DSStudio3DItem::isRunning() const { return m_running; @@ -214,6 +291,13 @@ void Q3DSStudio3DItem::createEngine() return; } + const QSurfaceFormat wformat = w->format(); + const QSurfaceFormat eformat = Q3DS::surfaceFormat(); + if (wformat.version() != eformat.version() || wformat.profile() != eformat.profile()) { + qCDebug(lcStudio3D) << "Adopting surface format from QQuickWindow:" << wformat; + Q3DS::adoptSurfaceFormat(wformat); + } + m_engine = new Q3DSEngine; engineTracker.insert(m_engine); diff --git a/src/imports/studio3d/q3dssubpresentationsettings.cpp b/src/imports/studio3d/q3dssubpresentationsettings.cpp index 0eabd1f..e8ffcea 100644 --- a/src/imports/studio3d/q3dssubpresentationsettings.cpp +++ b/src/imports/studio3d/q3dssubpresentationsettings.cpp @@ -47,4 +47,86 @@ QQmlListProperty<Q3DSInlineQmlSubPresentation> Q3DSSubPresentationSettings::qmlS return QQmlListProperty<Q3DSInlineQmlSubPresentation>(this, m_list); } +/*! + \qmltype SubPresentationSettings + \inqmlmodule QtStudio3D + \ingroup 3dstudioruntime2 + \brief Settings for sub-presentations. + + This type enables specifying a QML sub-presentation directly in the QML. + + A QML sub-presentation is a Qt Quick scene that is rendered to a texture + and then used either as the contents of Qt 3D Studio layer or as a texture + map. The contents of such a sub-presentation can be provided in two ways: + by a separate \c{.qml} file, or directly under the Studio3D element. + SubPresentationSettings is the enabler for the latter. + + \section2 Usage + + \qml + Studio3D { + id: studio3D + Presentation { + source: "file:///presentation.uia" + SubPresentationSettings { + qmlStreams: [ + QmlStream { + presentationId: "sub-presentation-id" + Item { + width: 1024 + height: 1024 + // ... other Qt Quick items + } + } + ] + } + } + } + \endqml + */ + +/*! + \qmlproperty list<QmlStream> SubPresentationSettings::qmlStreams + + Holds the list of QmlStream children. + */ + +/*! + \qmltype QmlStream + \inqmlmodule QtStudio3D + \ingroup 3dstudioruntime2 + \brief QML stream. + + This type allows attaching QML sub-presentation with a quick item. The item is rendered to a + texture and used as a part of a Qt 3D Studio presentation. + + The sub-presentation element must be specified in the \e assets element of the presentation + .uia file: + + \badcode + <assets ...> + <presentation-qml id="presentation-id" args="preview-presentation.qml" /> + </assets> + \endcode + + The \c presentation-id attribute must contain a unique ID of the sub-presentation. + The \c args attribute may contain an optional preview version of the item, which is only + used in the Viewer application. + */ + +/*! + \qmlproperty string QmlStream::presentationId + + Holds the string ID of the sub-presentation the item is attached to. The id must be one of + the \c presentation-qml IDs specified in the .uia file. + */ + +/*! + \qmlproperty Item QmlStream::item + + Holds the item attached to the sub-presentation. The item size is used as the the size of the + texture the item is rendered to. Default values \c{(256, 256)} are used if the item doesn't + specify a size. + */ + QT_END_NAMESPACE diff --git a/src/runtime/api/q3dsdatainput.cpp b/src/runtime/api/q3dsdatainput.cpp index 9341c04..69cafe3 100644 --- a/src/runtime/api/q3dsdatainput.cpp +++ b/src/runtime/api/q3dsdatainput.cpp @@ -32,18 +32,31 @@ QT_BEGIN_NAMESPACE -Q3DSDataInput::Q3DSDataInput(QObject *parent) - : QObject(*new Q3DSDataInputPrivate, parent) -{ -} +/*! + \class Q3DSDataInput + \inmodule 3dstudioruntime2 + \since Qt 3D Studio 2.0 + + \brief Controls a data input entry in a Qt 3D Studio presentation. + + This class is a convenience class for controlling a data input in a presentation. -Q3DSDataInput::Q3DSDataInput(const QString &name, QObject *parent) + \sa Q3DSPresentation +*/ + +/*! + \internal + */ +Q3DSDataInput::Q3DSDataInput(QObject *parent) : QObject(*new Q3DSDataInputPrivate, parent) { - Q_D(Q3DSDataInput); - d->name = name; } +/*! + Constructs a Q3DSDataInput instance and initializes the \a name. The + constructed instance is automatically associated with the specified \a + presentation. An optional \a parent object can be specified. + */ Q3DSDataInput::Q3DSDataInput(Q3DSPresentation *presentation, const QString &name, QObject *parent) : QObject(*new Q3DSDataInputPrivate, parent) { @@ -52,15 +65,29 @@ Q3DSDataInput::Q3DSDataInput(Q3DSPresentation *presentation, const QString &name d->presentation = presentation; } +/*! + \internal + */ Q3DSDataInput::Q3DSDataInput(Q3DSDataInputPrivate &dd, QObject *parent) : QObject(dd, parent) { } +/*! + Destructor. + */ Q3DSDataInput::~Q3DSDataInput() { } +/*! + \property Q3DSDataInput::name + + Specifies the name of the controlled data input element in the + presentation. This property must be set before setting the value property. + The initial value is provided via the constructor in practice, but the name + can also be changed later on, if desired. + */ QString Q3DSDataInput::name() const { Q_D(const Q3DSDataInput); @@ -76,6 +103,19 @@ void Q3DSDataInput::setName(const QString &name) } } +/*! + \property Q3DSDataInput::value + + Specifies the value of the controlled data input element in the + presentation. + + The value of this property only accounts for changes done via the same + Q3DSDataInput instance. If the value of the same data input in the + presentation is changed elsewhere, for example via presentation scripting, + those changes are not reflected in the value of this property. Due to this + uncertainty, this property treats all value sets as changes even if the + newly set value is the same value as the previous value. +*/ QVariant Q3DSDataInput::value() const { Q_D(const Q3DSDataInput); @@ -104,4 +144,37 @@ void Q3DSDataInputPrivate::sendValue() presentation->setDataInputValue(name, value); } +/*! + \qmltype DataInput + \instantiates Q3DSDataInput + \inqmlmodule QtStudio3D + \ingroup 3dstudioruntime2 + \brief Control type for data inputs in a Qt 3D Studio presentation. + + This type is a convenience type for controlling a data input in a presentation. + + \sa Studio3D, Presentation +*/ + +/*! + \qmlproperty string DataInput::name + + Specifies the name of the controlled data input element in the presentation. + This property must be set as part of DataInput declaration. +*/ + +/*! + \qmlproperty variant DataInput::value + + Specifies the value of the controlled data input element in the presentation. + The changes to the value property are queued and handled asynchronously before the + next frame is displayed. + + The value of this property only accounts for changes done via the same DataInput instance. + If the value of the same data input in the presentation is changed elsewhere, + for example via presentation scripting, those changes are not reflected in + the value of this property. Due to this uncertainty, this property treats all value sets as + changes even if the newly set value is the same value as the previous value. +*/ + QT_END_NAMESPACE diff --git a/src/runtime/api/q3dsdatainput.h b/src/runtime/api/q3dsdatainput.h index e685f78..c869c9e 100644 --- a/src/runtime/api/q3dsdatainput.h +++ b/src/runtime/api/q3dsdatainput.h @@ -52,7 +52,6 @@ class Q3DSV_EXPORT Q3DSDataInput : public QObject public: explicit Q3DSDataInput(QObject *parent = nullptr); - explicit Q3DSDataInput(const QString &name, QObject *parent = nullptr); Q3DSDataInput(Q3DSPresentation *presentation, const QString &name, QObject *parent = nullptr); ~Q3DSDataInput(); diff --git a/src/runtime/api/q3dselement.cpp b/src/runtime/api/q3dselement.cpp index ae119ae..3e72e83 100644 --- a/src/runtime/api/q3dselement.cpp +++ b/src/runtime/api/q3dselement.cpp @@ -32,18 +32,38 @@ QT_BEGIN_NAMESPACE +/*! + \class Q3DSElement + \inmodule 3dstudioruntime2 + \since Qt 3D Studio 2.0 + + \brief Controls a scene object in a Qt 3D Studio presentation. + + This class is a convenience class for controlling the properties of a scene + object (such as, model, material, camera, layer) in a Qt 3D Studio + presentation. + + \note The functionality of Q3DSElement is equivalent to + Q3DSPresentation::setAttribute(), Q3DSPresentation::getAttribute(), and + Q3DSPresentation::fireEvent(). + + \sa Q3DSPresentation, Q3DSWidget, Q3DSSurfaceViewer, Q3DSSceneElement + */ + +/*! + \internal + */ Q3DSElement::Q3DSElement(QObject *parent) : QObject(*new Q3DSElementPrivate, parent) { } -Q3DSElement::Q3DSElement(const QString &elementPath, QObject *parent) - : QObject(*new Q3DSElementPrivate, parent) -{ - Q_D(Q3DSElement); - d->elementPath = elementPath; -} - +/*! + Constructs a Q3DSElement instance controlling the scene object specified by + \a elementPath. An optional \a parent object can be specified. The + constructed instance is automatically associated with the specified \a + presentation. An optional \a parent object can be specified. + */ Q3DSElement::Q3DSElement(Q3DSPresentation *presentation, const QString &elementPath, QObject *parent) : QObject(*new Q3DSElementPrivate, parent) { @@ -52,15 +72,47 @@ Q3DSElement::Q3DSElement(Q3DSPresentation *presentation, const QString &elementP d->presentation = presentation; } +/*! + \internal + */ Q3DSElement::Q3DSElement(Q3DSElementPrivate &dd, QObject *parent) : QObject(dd, parent) { } +/*! + Destructor. + */ Q3DSElement::~Q3DSElement() { } +/*! + \property Q3DSElement::elementPath + + Holds the element path of the presentation element. + + An element path refers to an object in the scene either by name or id. The + latter is rarely used in application code since the unique IDs are not + exposed in the Qt 3D Studio application. To refer to an object by id, + prepend \c{#} to the name. Applications will typically refer to objects by + name. + + Names are not necessarily unique, however. To access an object with a + non-unique name, the path can be specified, for example, + \c{Scene.Layer.Camera}. Here the right camera object gets chosen even if + the scene contains other layers with the default camera names (for instance + \c{Scene.Layer2.Camera}). + + If the object is renamed to a unique name in the Qt 3D Studio application's + Timeline view, the path can be omitted. For example, if the camera in + question was renamed to \c MyCamera, applications can then simply pass \c + MyCamera as the element path. + + To access an object in a sub-presentation, prepend the name of the + sub-presentation followed by a colon, for example, + \c{SubPresentationOne:Scene.Layer.Camera}. + */ QString Q3DSElement::elementPath() const { Q_D(const Q3DSElement); @@ -76,6 +128,12 @@ void Q3DSElement::setElementPath(const QString &elementPath) } } +/*! + Returns the current value of an attribute (property) of the scene + object specified by elementPath. + + The \a attributeName is the \l{Attribute Names}{scripting name} of the attribute. + */ QVariant Q3DSElement::getAttribute(const QString &attributeName) const { Q_D(const Q3DSElement); @@ -85,6 +143,12 @@ QVariant Q3DSElement::getAttribute(const QString &attributeName) const return QVariant(); } +/*! + Sets the \a value of an attribute (property) of the scene object + specified by elementPath. + + The \a attributeName is the \l{Attribute Names}{scripting name} of the attribute. + */ void Q3DSElement::setAttribute(const QString &attributeName, const QVariant &value) { Q_D(Q3DSElement); @@ -92,6 +156,14 @@ void Q3DSElement::setAttribute(const QString &attributeName, const QVariant &val d->presentation->setAttribute(d->elementPath, attributeName, value); } +/*! + Dispatches an event with \a eventName on the scene object + specified by elementPath. + + Appropriate actions created in Qt 3D Studio or callbacks registered using + the registerForEvent() method in attached (behavior) scripts will be + executed in response to the event. + */ void Q3DSElement::fireEvent(const QString &eventName) { Q_D(Q3DSElement); @@ -104,4 +176,56 @@ void Q3DSElementPrivate::setPresentation(Q3DSPresentation *pres) presentation = pres; } +/*! + \qmltype Element + \instantiates Q3DSElement + \inqmlmodule QtStudio3D + \ingroup 3dstudioruntime2 + \brief Control type for elements in a Qt 3D Studio presentation. + + This type is a convenience type for managing a presentation element. + + All methods provided by this type are queued and handled asynchronously before the next + frame is displayed. + + \sa Studio3D, Presentation, SceneElement +*/ + +/*! + \qmlproperty string Element::elementPath + + Holds the element path of the presentation element. + This property must be set as part of Element declaration. + You can specify an element of a sub-presentation by adding "SubPresentationId:" + in front of the element path, for example \c{"SubPresentationOne:Scene"}. +*/ + +/*! + \qmlmethod void Element::setAttribute(string attributeName, variant value) + + Sets the \a value of an attribute on an element specified by this instance. + The \a attributeName is the \l{Attribute Names}{scripting name} of the attribute. + + The attribute must be preserved for scripting to be set by this function, or else it will fail. + An attribute is preserved if it is either \e{animated}, or + \e{an attribute on a master element that is unlinked and changed per-slide}. +*/ + +/*! + \qmlmethod void Element::fireEvent(string eventName) + + Dispatches an event with \a eventName on the element specified by this instance. + Appropriate actions created in Qt 3D Studio or callbacks registered using the registerForEvent() + method in attached scripts will be executed in response to the event. +*/ + +/*! + \qmlsignal Element::elementPathChanged(string elementPath) + + This signal is emitted when the element path property changes. + The new value is provided in the \a elementPath parameter. + + The corresponding handler is \c onElementPathChanged. +*/ + QT_END_NAMESPACE diff --git a/src/runtime/api/q3dselement.h b/src/runtime/api/q3dselement.h index ec62590..7e5d0b8 100644 --- a/src/runtime/api/q3dselement.h +++ b/src/runtime/api/q3dselement.h @@ -51,7 +51,6 @@ class Q3DSV_EXPORT Q3DSElement : public QObject public: explicit Q3DSElement(QObject *parent = nullptr); - explicit Q3DSElement(const QString &elementPath, QObject *parent = nullptr); Q3DSElement(Q3DSPresentation *presentation, const QString &elementPath, QObject *parent = nullptr); ~Q3DSElement(); diff --git a/src/runtime/api/q3dspresentation.cpp b/src/runtime/api/q3dspresentation.cpp index 0f0cf89..0a797b2 100644 --- a/src/runtime/api/q3dspresentation.cpp +++ b/src/runtime/api/q3dspresentation.cpp @@ -31,6 +31,40 @@ QT_BEGIN_NAMESPACE +/*! + \class Q3DSPresentation + \inmodule 3dstudioruntime2 + \since Qt 3D Studio 2.0 + + \brief Represents a Qt 3D Studio presentation. + + This class provides properties and methods for controlling a + presentation. + + Qt 3D Studio supports multiple presentations in one project. There + is always a main presentation and zero or more + sub-presentations. The sub-presentations are composed into the + main presentations either as contents of Qt 3D Studio layers or as + texture maps. + + In the filesystem each presentation corresponds to one \c{.uip} + file. When present, the \c{.uia} file ties these together by + specifying a name for each of the (sub-)presentations and + specifies which one is the main one. + + From the API point of view Q3DSPresentation corresponds to the + main presentation. The source property can refer either to a + \c{.uia} or \c{.uip} file. When specifying a file with \c{.uip} + extension and a \c{.uia} is present with the same name, the + \c{.uia} is loaded automatically and thus sub-presentation + information is available regardless. + + \note This class should not be instantiated directly when working with the + C++ APIs. Q3DSSurfaceViewer and Q3DSWidget create a Q3DSPresentation + instance implicitly. This can be queried via + Q3DSSurfaceViewer::presentation() or Q3DSWidget::presentation(). + */ + // Unlike in 3DS1, Q3DSPresentation here does not own the engine. This is due // to the delicate lifetime management needs due to Qt 3D under the hood: for // instance the Studio3D element has to carefully manage the underlying @@ -40,20 +74,41 @@ QT_BEGIN_NAMESPACE // Q3DSPresentationController (for common functionality), or individually by // Studio3D, Q3DSWidget, or Q3DSSurfaceViewer. +/*! + Constructs a new Q3DSPresentation with the given \a parent. + */ Q3DSPresentation::Q3DSPresentation(QObject *parent) : QObject(*new Q3DSPresentationPrivate, parent) { } +/*! + \internal + */ Q3DSPresentation::Q3DSPresentation(Q3DSPresentationPrivate &dd, QObject *parent) : QObject(dd, parent) { } +/*! + Destructor. + */ Q3DSPresentation::~Q3DSPresentation() { } +/*! + \property Q3DSPresentation::source + + Holds the name of the main presentation file (\c{*.uia} or + \c{*.uip}). This may be either a local file or qrc URL. + + The names of all further assets (image files for texture maps, qml + behavior scripts, mesh files) will be resolved relative to the + location of the presentation, unless they use absolute paths. This + allows bundling all assets next to the presentation in the Qt + resource system. +*/ QUrl Q3DSPresentation::source() const { Q_D(const Q3DSPresentation); @@ -128,6 +183,9 @@ void Q3DSPresentation::setProfileUiScale(float scale) } } +/*! + Reloads the presentation. + */ void Q3DSPresentation::reload() { Q_D(Q3DSPresentation); @@ -135,6 +193,21 @@ void Q3DSPresentation::reload() d->controller->handlePresentationReload(); } +/*! + Sets the \a value of a data input element \a name in the presentation. + + Data input provides a higher level, designer-driven alternative to + Q3DSElement and setAttribute(). Instead of exposing a large set of + properties with their intenal engine names, data input allows designers to + decide which properties should be writable by the application, and can + assign custom names to these data input entries, thus forming a + well-defined contract between the designer and the developer. + + In addition, data input also allows controlling the time line and the + current slide for time context objects (Scene or Component). Therefore it + is also an alternative to the goToSlide() and goToTime() family of APIs and + to Q3DSSceneElement. + */ void Q3DSPresentation::setDataInputValue(const QString &name, const QVariant &value) { Q_D(Q3DSPresentation); @@ -142,6 +215,14 @@ void Q3DSPresentation::setDataInputValue(const QString &name, const QVariant &va d->controller->handleDataInputValue(name, value); } +/*! + Dispatches an event with \a eventName on a specific element found in \a + elementPath. Appropriate actions created in Qt 3D Studio or callbacks + registered using the registerForEvent() method in attached (behavior) + scripts will be executed in response to the event. + + See setAttribute() for a description of \a elementPath. + */ void Q3DSPresentation::fireEvent(const QString &elementPath, const QString &eventName) { Q_D(Q3DSPresentation); @@ -149,6 +230,32 @@ void Q3DSPresentation::fireEvent(const QString &elementPath, const QString &even d->controller->handleFireEvent(elementPath, eventName); } +/*! + Moves the timeline for a time context (a Scene or a Component element) to a + specific position. The position is given in seconds in \a timeSeconds. + + If \a elementPath points to a time context, that element is + controlled. For all other element types the time context owning + that element is controlled instead. You can target the command to + a specific sub-presentation by adding "SubPresentationId:" in + front of the element path, for example + \c{"SubPresentationOne:Scene"}. + + The behavior when specifying a time before 0 or after the end time + for the current slide depends on the play mode of the slide: + + \list + \li \c{Stop at End} - values outside the valid time range instead clamp to the boundaries. + For example, going to time -5 is the same as going to time 0. + \li \c{Looping} - values outside the valid time range mod into the valid range. For example, + going to time -4 on a 10 second slide is the same as going to time 6. + \li \c{Ping Pong} - values outside the valid time range bounce off the ends. For example, + going to time -4 is the same as going to time 4 (assuming the time context is at least 4 seconds + long), while going to time 12 on a 10 second slide is the same as going to time 8. + \li \c{Ping} - values less than 0 are treated as time 0, while values greater than the endtime + bounce off the end (eventually hitting 0.) + \endlist + */ void Q3DSPresentation::goToTime(const QString &elementPath, float timeSeconds) { Q_D(Q3DSPresentation); @@ -156,6 +263,17 @@ void Q3DSPresentation::goToTime(const QString &elementPath, float timeSeconds) d->controller->handleGoToTime(elementPath, timeSeconds); } +/*! + Requests a time context (a Scene or a Component object) to change + to a specific slide by \a name. If the context is already on that + slide, playback will start over. + + If \a elementPath points to a time context, that element is + controlled. For all other element types the time context owning + that element is controlled instead. You can target the command to + a specific sub-presentation by adding "SubPresentationId:" in + front of the element path, for example \c{"SubPresentationOne:Scene"}. + */ void Q3DSPresentation::goToSlide(const QString &elementPath, const QString &name) { Q_D(Q3DSPresentation); @@ -163,6 +281,17 @@ void Q3DSPresentation::goToSlide(const QString &elementPath, const QString &name d->controller->handleGoToSlideByName(elementPath, name); } +/*! + Requests a time context (a Scene or a Component object) to change + to a specific slide by \a index. If the context is already on that + slide, playback will start over. + + If \a elementPath points to a time context, that element is + controlled. For all other element types the time context owning + that element is controlled instead. You can target the command to + a specific sub-presentation by adding "SubPresentationId:" in + front of the element path, for example \c{"SubPresentationOne:Scene"}. + */ void Q3DSPresentation::goToSlide(const QString &elementPath, int index) { Q_D(Q3DSPresentation); @@ -170,6 +299,18 @@ void Q3DSPresentation::goToSlide(const QString &elementPath, int index) d->controller->handleGoToSlideByIndex(elementPath, index); } +/*! + Requests a time context (a Scene or a Component object) to change to the + next or previous slide, depending on the value of \a next. If the context + is already at the last or first slide, \a wrap defines if wrapping over to + the first or last slide, respectively, occurs. + + If \a elementPath points to a time context, that element is controlled. For + all other element types the time context owning that element is controlled + instead. You can target the command to a specific sub-presentation by + adding "SubPresentationId:" in front of the element path, for example + \c{"SubPresentationOne:Scene"}. + */ void Q3DSPresentation::goToSlide(const QString &elementPath, bool next, bool wrap) { Q_D(Q3DSPresentation); @@ -177,6 +318,15 @@ void Q3DSPresentation::goToSlide(const QString &elementPath, bool next, bool wra d->controller->handleGoToSlideByDirection(elementPath, next, wrap); } +/*! + Returns the value of an attribute (property) on the object specified by \a + elementPath. The \a attributeName is the \l{Attribute Names}{scripting + name} of the attribute. + + See setAttribute() for a description of \a elementPath. + + \sa setAttribute + */ QVariant Q3DSPresentation::getAttribute(const QString &elementPath, const QString &attributeName) { Q_D(Q3DSPresentation); @@ -186,6 +336,34 @@ QVariant Q3DSPresentation::getAttribute(const QString &elementPath, const QStrin return QVariant(); } +/*! + Sets the \a value of an attribute (property) on the object specified by + \a elementPath. The \a attributeName is the \l{Attribute Names}{scripting + name} of the attribute. + + An element path refers to an object in the scene either by name or id. The + latter is rarely used in application code since the unique IDs are not + exposed in the Qt 3D Studio application. To refer to an object by id, + prepend \c{#} to the name. Applications will typically refer to objects by + name. + + Names are not necessarily unique, however. To access an object with a + non-unique name, the path can be specified, for example, + \c{Scene.Layer.Camera}. Here the right camera object gets chosen even if + the scene contains other layers with the default camera names (for instance + \c{Scene.Layer2.Camera}). + + If the object is renamed to a unique name in the Qt 3D Studio application's + Timeline view, the path can be omitted. For example, if the camera in + question was renamed to \c MyCamera, applications can then simply pass \c + MyCamera as the element path. + + To access an object in a sub-presentation, prepend the name of the + sub-presentation followed by a colon, for example, + \c{SubPresentationOne:Scene.Layer.Camera}. + + \sa getAttribute + */ void Q3DSPresentation::setAttribute(const QString &elementPath, const QString &attributeName, const QVariant &value) { Q_D(Q3DSPresentation); @@ -292,4 +470,182 @@ void Q3DSPresentationPrivate::registerInlineQmlSubPresentations(const QVector<Q3 inlineQmlSubPresentations += list; } +/*! + \qmltype Presentation + \instantiates Q3DSPresentation + \inqmlmodule QtStudio3D + \ingroup 3dstudioruntime2 + + \brief Control type for Qt 3D Studio presentations. + + This type provides properties and methods for controlling a presentation. + + All methods provided by this type are queued and handled asynchronously before the next + frame is displayed. + + \sa Studio3D +*/ + +/*! + \qmlproperty url Presentation::source + + Holds the presentation source (\c{*.uia} or \c{*.uip}) file location. + May be either a file URL or a qrc URL. +*/ + +/*! + \qmlproperty SubPresentationSettings Presentation::subPresentationSettings + + Holds the settings for the subpresentations in the Qt 3D Studio presentation. + + This property is read-only. +*/ + +/*! + \qmlmethod void Presentation::goToSlide(string elementPath, string name) + + Requests a time context (a Scene or a Component element) to change to a specific slide + by \a name. If the context is already on that slide playback will start over. + + If \a elementPath points to a time context, that element is controlled. For + all other element types the time context owning that element is controlled instead. + You can target the command to a specific sub-presentation by adding "SubPresentationId:" in + front of the element path, for example \c{"SubPresentationOne:Scene"}. +*/ + +/*! + \qmlmethod void Presentation::goToSlide(string elementPath, int index) + + Requests a time context (a Scene or a Component element) to change to a specific slide by + index \a index. If the context is already on that slide playback will start over. + + If \a elementPath points to a time context, that element is controlled. For + all other element types the time context owning that element is controlled instead. + You can target the command to a specific sub-presentation by adding "SubPresentationId:" in + front of the element path, for example \c{"SubPresentationOne:Scene"}. +*/ + +/*! + \qmlmethod void Presentation::goToSlide(string elementPath, bool next, bool wrap) + + Requests a time context (a Scene or a Component element) to change to the next or the + previous slide, depending on the value of \a next. If the context is already at the + last or first slide, \a wrap defines if change occurs to the opposite end. + + If \a elementPath points to a time context, that element is controlled. For + all other element types the time context owning that element is controlled instead. + You can target the command to a specific sub-presentation by adding "SubPresentationId:" in + front of the element path, for example \c{"SubPresentationOne:Scene"}. +*/ + +/*! + \qmlmethod void Presentation::goToTime(string elementPath, real time) + + Sets a time context (a Scene or a Component element) to a specific playback \a time in seconds. + + If \a elementPath points to a time context, that element is controlled. For + all other element types the time context owning that element is controlled instead. + You can target the command to a specific sub-presentation by adding "SubPresentationId:" in + front of the element path, for example \c{"SubPresentationOne:Scene"}. + + The behavior when specifying a time before 0 or after the end time for the current slide depends + on the play mode of the slide: + \list + \li \c{Stop at End} - values outside the valid time range instead clamp to the boundaries. + For example, going to time -5 is the same as going to time 0. + \li \c{Looping} - values outside the valid time range mod into the valid range. For example, + going to time -4 on a 10 second slide is the same as going to time 6. + \li \c{Ping Pong} - values outside the valid time range ‘bounce’ off the ends. For example, + going to time -4 is the same as going to time 4 (assuming the time context is at least 4 seconds + long), while going to time 12 on a 10 second slide is the same as going to time 8. + \li \c{Ping} - values less than 0 are treated as time 0, while values greater than the endtime + bounce off the end (eventually hitting 0.) + \endlist +*/ + +/*! + \qmlmethod void Presentation::setAttribute(string elementPath, string attributeName, + variant value) + + Sets the \a value of an attribute on an element found at \a elementPath. The \a attributeName is + the \l{Attribute Names}{scripting name} of the attribute. + + You can target the command to a specific sub-presentation by adding "SubPresentationId:" in + front of the element path, for example \c{"SubPresentationOne:Scene.Mesh.Material"}. + + The attribute must be preserved for scripting to be set by this function, or else it will fail. + An attribute is preserved if it is either \e{animated}, or + \e{an attribute on a master element that is unlinked and changed per-slide}. +*/ + +/*! + \qmlmethod void Presentation::setPresentationActive(string id, bool active) + + Stops or starts updates to a sub-presentation based on the \a active flag. The presentation is + referenced to by the \a id, which is the name of the presentation without the \c{.uip}. + + Making a presentation inactive prevents any elements, behaviors, and animations within it from + updating. It also prevents any events within that presentation from being processed. It does + not, however, prevent the presentation from rendering. An inactive presentation will continue + to render using its last-updated information. + + Explicitly inactivating presentations can provide a significant performance increase, depending + on the number and size of the presentations that are inactive. Inactive presentations are not + ‘paused’. When the presentation is re-activated, animations will resume at the time they should + be had they been running, not where they were when the presentation was made inactive. +*/ + +/*! + \qmlmethod void Presentation::fireEvent(string elementPath, string eventName) + + Dispatches an event with \a eventName on a specific element found in \a elementPath. Appropriate + Appropriate actions created in Qt 3D Studio or callbacks registered using the registerForEvent() + method in attached scripts will be executed in response to the event. + + You can target the command to a specific sub-presentation by adding "SubPresentationId:" in + front of the element path, for example \c{"SubPresentationOne:Scene.Mesh"}. +*/ + +/*! + \qmlmethod void Presentation::setGlobalAnimationTime(int64 milliseconds) + + Sets the global animation time to \a milliseconds. Setting the global animation time to a + non-zero value will disable the automatic animation timer. Setting the value to zero + resumes automatic animation timer. +*/ + +/*! + \qmlmethod void Presentation::setDataInputValue(string name, variant value) + \since QtStudio3D 1.1 + + Sets the \a value of a data input element \a name in the presentation. +*/ + +/*! + \qmlsignal Presentation::slideEntered(string elementPath, int index, string name) + + This signal is emitted when a slide is entered in the presentation. + The \a elementPath specifies the time context (a Scene or a Component element) owning the + entered slide. + The \a index and \a name contain the index and the name of the entered slide. +*/ + +/*! + \qmlsignal Presentation::slideExited(string elementPath, int index, string name) + + This signal is emitted when a slide is exited in the presentation. + The \a elementPath specifies the time context (a Scene or a Component element) owning the + exited slide. + The \a index and \a name contain the index and the name of the exited slide. +*/ + +/*! + \qmlsignal Presentation::sourceChanged(url source) + + This signal is emitted when the source property has changed. + The new value is provided in the \a source parameter. + + The corresponding handler is \c onSourceChanged. +*/ + QT_END_NAMESPACE diff --git a/src/runtime/api/q3dssceneelement.cpp b/src/runtime/api/q3dssceneelement.cpp index f8b3e23..6b3c161 100644 --- a/src/runtime/api/q3dssceneelement.cpp +++ b/src/runtime/api/q3dssceneelement.cpp @@ -32,18 +32,39 @@ QT_BEGIN_NAMESPACE -Q3DSSceneElement::Q3DSSceneElement(QObject *parent) - : Q3DSElement(*new Q3DSSceneElementPrivate, parent) -{ -} +/*! + \class Q3DSSceneElement + \inherits Q3DSElement + \inmodule 3dstudioruntime2 + \since Qt 3D Studio 2.0 + + \brief Controls the special Scene or Component scene objects in a Qt 3D + Studio presentation. + + This class is a convenience class for controlling the properties of Scene + and Component objects in the scene. These are special since they have a + time context, meaning they control a timline and a set of associated + slides. + + \note The functionality of Q3DSSceneElement is equivalent to + Q3DSPresentation::goToTime() and Q3DSPresentation::goToSlide(). + + \sa Q3DSPresentation, Q3DSWidget, Q3DSSurfaceViewer, Q3DSElement + */ -Q3DSSceneElement::Q3DSSceneElement(const QString &elementPath, QObject *parent) +/*! + \internal + */ +Q3DSSceneElement::Q3DSSceneElement(QObject *parent) : Q3DSElement(*new Q3DSSceneElementPrivate, parent) { - Q_D(Q3DSSceneElement); - d->elementPath = elementPath; } +/*! + Constructs a Q3DSSceneElement instance and associated it with the object + specified by \a elementPath and the given \a presentation. An optional \a + parent object can be specified. + */ Q3DSSceneElement::Q3DSSceneElement(Q3DSPresentation *presentation, const QString &elementPath, QObject *parent) : Q3DSElement(*new Q3DSSceneElementPrivate, parent) { @@ -52,33 +73,77 @@ Q3DSSceneElement::Q3DSSceneElement(Q3DSPresentation *presentation, const QString d->presentation = presentation; } +/*! + \internal + */ Q3DSSceneElement::Q3DSSceneElement(Q3DSSceneElementPrivate &dd, QObject *parent) : Q3DSElement(dd, parent) { } +/*! + Destructor. + */ Q3DSSceneElement::~Q3DSSceneElement() { } +/*! + \property Q3DSSceneElement::currentSlideIndex + + Holds the index of the currently active slide of the tracked time context. + + \note If this property is set to something else than the default slide for + the scene at the initial declaration of SceneElement, a changed signal for + the default slide may stil be emitted before the slide changes to the + desired one. This happens in order to ensure we end up with the index of + the slide that is actually shown even if the slide specified in the initial + declaration is invalid. +*/ int Q3DSSceneElement::currentSlideIndex() const { Q_D(const Q3DSSceneElement); return d->currentSlideIndex; } +/*! + \property Q3DSSceneElement::previousSlideIndex + + Holds the index of the previously active slide of the tracked time context. + + This property is read-only. +*/ int Q3DSSceneElement::previousSlideIndex() const { Q_D(const Q3DSSceneElement); return d->previousSlideIndex; } +/*! + \property Q3DSSceneElement::currentSlideName + + Holds the name of the currently active slide of the tracked time context. + + \note If this property is set to something else than the default slide for + the scene at the initial declaration of SceneElement, a changed signal for + the default slide may stil be emitted before the slide changes to the + desired one. This happens in order to ensure we end up with the index of + the slide that is actually shown even if the slide specified in the initial + declaration is invalid. +*/ QString Q3DSSceneElement::currentSlideName() const { Q_D(const Q3DSSceneElement); return d->currentSlideName; } +/*! + \property Q3DSSceneElement::previousSlideName + + Holds the name of the previously active slide of the tracked time context. + + This property is read-only. +*/ QString Q3DSSceneElement::previousSlideName() const { Q_D(const Q3DSSceneElement); @@ -105,6 +170,12 @@ void Q3DSSceneElement::setCurrentSlideName(const QString ¤tSlideName) d->pendingSlideSetName = currentSlideName; // defer to sendPendingValues() } +/*! + Requests a time context (a Scene or a Component object) to change to the + next or previous slide, depending on the value of \a next. If the context + is already at the last or first slide, \a wrap defines if wrapping over to + the first or last slide, respectively, occurs. + */ void Q3DSSceneElement::goToSlide(bool next, bool wrap) { Q_D(Q3DSSceneElement); @@ -112,6 +183,10 @@ void Q3DSSceneElement::goToSlide(bool next, bool wrap) d->presentation->goToSlide(d->elementPath, next, wrap); } +/*! + Moves the timeline for a time context (a Scene or a Component element) to a + specific position. The position is given in seconds in \a timeSeconds. + */ void Q3DSSceneElement::goToTime(float timeSeconds) { Q_D(Q3DSSceneElement); @@ -171,6 +246,131 @@ void Q3DSSceneElementPrivate::setPresentation(Q3DSPresentation *pres) q, SLOT(_q_onSlideEntered(QString,int,QString))); } +/*! + \qmltype SceneElement + \instantiates Q3DSSceneElement + \inherits Element + \inqmlmodule QtStudio3D + \ingroup 3dstudioruntime2 + \brief Control type for scene and component elements in a Qt 3D Studio presentation. + + This type is a convenience type for managing the slides of a single + time context (a Scene or a Component element) of a presentation. + + All methods provided by this type are queued and handled asynchronously before the next + frame is displayed. + + \sa Studio3D, Presentation, Element +*/ + +/*! + \qmlproperty int SceneElement::currentSlideIndex + + Holds the index of the currently active slide of the tracked time context. + + Changing the current slide via this property is asynchronous. The property + value will not actually change until the next frame has been processed, and + even then only if the new slide was valid. + + \note If this property is set to something else than the default slide for the scene at the + initial declaration of SceneElement, you will still get an extra changed signal for the + default slide before the slide changes to the desired one. This happens in order to ensure + we end up with the index of the slide that is actually shown even if the slide specified in the + initial declaration is invalid. +*/ + +/*! + \qmlproperty int SceneElement::previousSlideIndex + + Holds the index of the previously active slide of the tracked time context. + + This property is read-only. +*/ + +/*! + \qmlproperty string SceneElement::currentSlideName + + Holds the name of the currently active slide of the tracked time context. + + Changing the current slide via this property is asynchronous. The property + value will not actually change until the next frame has been processed, and + even then only if the new slide was valid. + + \note If this property is set to something else than the default slide for the scene at the + initial declaration of SceneElement, you will still get an extra changed signal for the + default slide before the slide changes to the desired one. This happens in order to ensure + we end up with the name of the slide that is actually shown even if the slide specified in the + initial declaration is invalid. +*/ + +/*! + \qmlproperty string SceneElement::previousSlideName + + Holds the name of the previously active slide of the tracked time context. + + This property is read-only. +*/ + +/*! + \qmlsignal SceneElement::currentSlideIndexChanged(int currentSlideIndex) + + This signal is emitted when the current slide changes. + The new value is provided in the \a currentSlideIndex parameter. + + This signal is always emitted with currentSlideNameChanged. + + The corresponding handler is \c onCurrentSlideIndexChanged. +*/ + +/*! + \qmlsignal SceneElement::previousSlideIndexChanged(int previousSlideIndex) + + This signal is emitted when the previous slide changes. + The new value is provided in the \a previousSlideIndex parameter. + + This signal is always emitted with previousSlideNameChanged. + + The corresponding handler is \c onPreviousSlideIndexChanged. +*/ + +/*! + \qmlsignal SceneElement::currentSlideNameChanged(string currentSlideName) + + This signal is emitted when the current slide changes. + The new value is provided in the \a currentSlideName parameter. + + This signal is always emitted with currentSlideIndexChanged. + + The corresponding handler is \c onCurrentSlideNameChanged. +*/ + +/*! + \qmlsignal SceneElement::previousSlideNameChanged(string previousSlideName) + + This signal is emitted when the previous slide changes. + The new value is provided in the \a previousSlideName parameter. + + This signal is always emitted with previousSlideIndexChanged. + + The corresponding handler is \c onPreviousSlideNameChanged. +*/ + +/*! + \qmlmethod void SceneElement::goToSlide(bool next, bool wrap) + + Requests a time context (a Scene or a Component element) to change to the next or the + previous slide, depending on the value of \a next. If the context is already at the + last or first slide, \a wrap defines if change occurs to the opposite end. +*/ + +/*! + \qmlmethod void SceneElement::goToTime(string elementPath, real time) + + Sets a time context (a Scene or a Component element) to a specific playback \a time in seconds. + + For behavior details, see Presentation::goToTime() documentation. +*/ + QT_END_NAMESPACE #include "moc_q3dssceneelement.cpp" diff --git a/src/runtime/api/q3dssceneelement.h b/src/runtime/api/q3dssceneelement.h index d8eba18..b7726d3 100644 --- a/src/runtime/api/q3dssceneelement.h +++ b/src/runtime/api/q3dssceneelement.h @@ -52,7 +52,6 @@ class Q3DSV_EXPORT Q3DSSceneElement : public Q3DSElement public: explicit Q3DSSceneElement(QObject *parent = nullptr); - explicit Q3DSSceneElement(const QString &elementPath, QObject *parent = nullptr); Q3DSSceneElement(Q3DSPresentation *presentation, const QString &elementPath, QObject *parent = nullptr); ~Q3DSSceneElement(); diff --git a/src/runtime/api/q3dssurfaceviewer.cpp b/src/runtime/api/q3dssurfaceviewer.cpp index 853b96b..8ecb6c3 100644 --- a/src/runtime/api/q3dssurfaceviewer.cpp +++ b/src/runtime/api/q3dssurfaceviewer.cpp @@ -45,6 +45,56 @@ QT_BEGIN_NAMESPACE +/*! + \class Q3DSSurfaceViewer + \inmodule 3dstudioruntime2 + \since Qt 3D Studio 2.0 + + \brief Renders a Qt 3D Studio presentation on a QWindow or an offscreen + render target using OpenGL. + + Q3DSSurfaceViewer is used to render Qt 3D Studio presentations onto a + QSurface. In practice this means two types of uses: rendering to an + on-screen QWindow, or rendering to an offscreen render target (typically an + OpenGL texture via a framebuffer object and a QOffscreenSurface). + + \section2 Example Usage + + \code + int main(int argc, char *argv[]) + { + QGuiApplication app(argc, argv); + + QOpenGLContext context; + context.create(); + + QWindow window; + window.setSurfaceType(QSurface::OpenGLSurface); + window.setFormat(context.format()); + window.create(); + + Q3DSSurfaceViewer viewer; + viewer.presentation()->setSource(QUrl(QStringLiteral("qrc:/my_presentation.uip"))); + viewer.setUpdateInterval(0); // enable automatic updates + + // Register a scene object for slide management (optional) + Q3DSSceneElement scene(viewer.presentation(), QStringLiteral("Scene")); + + // Register an element object for attribute setting (optional) + Q3DSElement element(viewer.presentation(), QStringLiteral("myCarModel")); + + viewer.create(&window, &context); + + w.resize(1024, 768); + w.show(); + + return app.exec(); + } + \endcode + + \sa Q3DSWidget + */ + Q3DSSurfaceViewer::Q3DSSurfaceViewer(QObject *parent) : QObject(*new Q3DSSurfaceViewerPrivate, parent) { @@ -67,12 +117,35 @@ Q3DSSurfaceViewer::~Q3DSSurfaceViewer() // "use this custom FBO as-is". Changing to int would be wrong too since the ID // is a GLuint in practice. +/*! + Initializes Q3DSSurfaceViewer to render the presentation to the given + \a surface using the \a context. + + The source property of the attached presentation must be set before the + viewer can be initialized. + + Returns whether the initialization succeeded. + + \sa running, Q3DSPresentation::source, presentation() +*/ bool Q3DSSurfaceViewer::create(QSurface *surface, QOpenGLContext *context) { Q_D(Q3DSSurfaceViewer); return d->doCreate(surface, context, 0, false); } +/*! + Initializes Q3DSSurfaceViewer to render the presentation to the given + \a surface using the \a context and optional framebuffer id (\a fboId). If + \a fboId is omitted, it defaults to zero. + + The source property of the attached presentation must be set before the + viewer can be initialized. + + Returns whether the initialization succeeded. + + \sa running, Q3DSPresentation::source, presentation() +*/ bool Q3DSSurfaceViewer::create(QSurface *surface, QOpenGLContext *context, uint fboId) { Q_D(Q3DSSurfaceViewer); @@ -114,12 +187,18 @@ void Q3DSSurfaceViewer::destroy() d->fbo = 0; } +/*! + Returns the presentation object used by the Q3DSSurfaceViewer. +*/ Q3DSPresentation *Q3DSSurfaceViewer::presentation() const { Q_D(const Q3DSSurfaceViewer); return d->presentation; } +/*! + Returns the settings object used by the Q3DSSurfaceViewer. +*/ Q3DSViewerSettings *Q3DSSurfaceViewer::settings() const { Q_D(const Q3DSSurfaceViewer); @@ -132,6 +211,14 @@ QString Q3DSSurfaceViewer::error() const return d->error; } +/*! + \property Q3DSSurfaceViewer::running + + The value of this property is \c true when the viewer has been initialized + and the presentation is running. + + This property is read-only. +*/ bool Q3DSSurfaceViewer::isRunning() const { Q_D(const Q3DSSurfaceViewer); @@ -153,6 +240,22 @@ void Q3DSSurfaceViewer::setSize(const QSize &size) } } +/*! + \property Q3DSSurfaceViewer::autoSize + + Specifies whether the viewer should change the size of the presentation + automatically to match the surface size when surface size changes. The + \l{Q3DSSurfaceViewer::size}{size} property is updated automatically + whenever the viewer is \l{Q3DSSurfaceViewer::update()}{updated} if this + property value is \c{true}. + + When rendering offscreen, via a QOffscreenSurface, this property must be + set to \c{false} by the application since it is then up to the application + to provide a QOpenGLFramebufferObject with the desired size. The size of + the Q3DSSurfaceViewer must be set to the same value. + + The default value is \c{true}. +*/ bool Q3DSSurfaceViewer::autoSize() const { Q_D(const Q3DSSurfaceViewer); @@ -168,6 +271,17 @@ void Q3DSSurfaceViewer::setAutoSize(bool autoSize) } } +/*! + \property Q3DSSurfaceViewer::updateInterval + + Holds the viewer update interval in milliseconds. If the value is negative, + the viewer doesn't update the presentation automatically. + + The default value is -1, meaning there are no automatic updates and + update() must be called manually. + + \sa update() +*/ int Q3DSSurfaceViewer::updateInterval() const { Q_D(const Q3DSSurfaceViewer); @@ -190,18 +304,33 @@ void Q3DSSurfaceViewer::setUpdateInterval(int interval) } } +/*! + Returns the framebuffer id given in initialization. + + \sa create() +*/ uint Q3DSSurfaceViewer::fboId() const { Q_D(const Q3DSSurfaceViewer); return d->fbo; } +/*! + Returns the surface given in initialization. + + \sa create() +*/ QSurface *Q3DSSurfaceViewer::surface() const { Q_D(const Q3DSSurfaceViewer); return d->surface; } +/*! + Returns the context given in initialization. + + \sa create() +*/ QOpenGLContext *Q3DSSurfaceViewer::context() const { Q_D(const Q3DSSurfaceViewer); @@ -210,6 +339,9 @@ QOpenGLContext *Q3DSSurfaceViewer::context() const extern Q_GUI_EXPORT QImage qt_gl_read_framebuffer(const QSize &size, bool alpha_format, bool include_alpha); +/*! + Updates the surface viewer with a new frame. +*/ void Q3DSSurfaceViewer::update() { Q_D(Q3DSSurfaceViewer); @@ -272,6 +404,13 @@ void Q3DSSurfaceViewer::update() emit frameUpdate(); } +/*! + Grabs the data rendered to the framebuffer into an image using the given \a + rect. The \a rect parameter is optional. If it is omitted, the whole + framebuffer is captured. + + \note This is a potentially expensive operation. +*/ QImage Q3DSSurfaceViewer::grab(const QRect &rect) { Q_D(Q3DSSurfaceViewer); diff --git a/src/runtime/api/q3dsviewersettings.cpp b/src/runtime/api/q3dsviewersettings.cpp index ba1249a..a0d91ea 100644 --- a/src/runtime/api/q3dsviewersettings.cpp +++ b/src/runtime/api/q3dsviewersettings.cpp @@ -32,6 +32,26 @@ QT_BEGIN_NAMESPACE +/*! + \class Q3DSViewerSettings + \inmodule 3dstudioruntime2 + \since Qt 3D Studio 2.0 + + \brief Qt 3D Studio presentation viewer settings. + + Q3DSViewerSettings provides properties to define presentation independent + viewer settings. + + \note As of Qt 3D Studio 2.0 this class is provided mainly for + compatibility reasons. Most functions are not applicable or are not + currently supported and will be silently ignored. + + \note This class should not be instantiated directly when working with the + C++ APIs. Q3DSSurfaceViewer and Q3DSWidget create a Q3DSViewerSettings + instance implicitly. This can be queried via Q3DSSurfaceViewer::settings() + or Q3DSWidget::settings(). + */ + Q3DSViewerSettings::Q3DSViewerSettings(QObject *parent) : QObject(*new Q3DSViewerSettingsPrivate, parent) { @@ -52,6 +72,17 @@ QColor Q3DSViewerSettings::matteColor() const return d->matteColor; } +/*! + \property Q3DSViewerSettings::showRenderStats + + If this property is set to \c{true}, the interactive statistics and profile + view is displayed in-scene, on top of the 3D content. + + \note This feature can be disabled at build time, in which case this + property has no effect. + + Default value is \c{false}. +*/ bool Q3DSViewerSettings::isShowingRenderStats() const { Q_D(const Q3DSViewerSettings); @@ -129,4 +160,24 @@ void Q3DSViewerSettings::load(const QString &group, qWarning() << Q_FUNC_INFO << "not implemented"; } +/*! + \qmltype ViewerSettings + \instantiates Q3DSViewerSettings + \inqmlmodule QtStudio3D + \ingroup 3dstudioruntime2 + \brief Qt 3D Studio presentation viewer settings. + + This type provides properties to define presentation independent viewer settings. + + \sa Studio3D +*/ + +/*! + \qmlproperty bool ViewerSettings::showRenderStats + + If this property is set to \c{true}, render statistics are displayed on the upper part + of the viewer. + Default value is \c{false}. +*/ + QT_END_NAMESPACE diff --git a/src/runtime/api/q3dswidget.cpp b/src/runtime/api/q3dswidget.cpp index 6fb6d3e..8cdd898 100644 --- a/src/runtime/api/q3dswidget.cpp +++ b/src/runtime/api/q3dswidget.cpp @@ -44,12 +44,35 @@ QT_BEGIN_NAMESPACE /*! \class Q3DSWidget - \inmodule 3dstudioruntime2 + \since Qt 3D Studio 2.0 + \inherits QOpenGLWidget + + \brief A widget that renders Qt 3D Studio presentations using OpenGL. + + Q3DSWidget is a widget that can be used to embed Qt 3D Studio presentations + into QWidget-based applications. + + Q3DSWidget is used to specify a render widget for Qt 3D Studio + presentation. It subclasses QOpenGLWidget, which means all considerations + that should be taken when working with QOpenGLWidget apply to Q3DSWidget as + well. Refer to the QOpenGLWidget documentation for details. + + \section2 Example Usage - \brief Widget + \code + Q3DSWidget *viewer = new Q3DSWidget(parentWidget); + viewer->presentation()->setSource(QUrl(QStringLiteral("qrc:/my_presentation.uip"))); + viewer->setUpdateInterval(0); - blah + // Register a scene element object for slide management (optional) + Q3DSSceneElement scene(viewer->presentation(), QStringLiteral("Scene")); + + // Register an element object for attribute setting (optional) + Q3DSElement element(viewer->presentation(), QStringLiteral("myCarModel")); + \endcode + + \sa Q3DSSurfaceViewer */ Q3DSWidget::Q3DSWidget(QWidget *parent) @@ -65,12 +88,18 @@ Q3DSWidget::~Q3DSWidget() delete d_ptr; } +/*! + Returns the presentation object used by the Q3DSWidget. + */ Q3DSPresentation *Q3DSWidget::presentation() const { Q_D(const Q3DSWidget); return d->presentation; } +/*! + Returns the settings object used by the Q3DSWidget. + */ Q3DSViewerSettings *Q3DSWidget::settings() const { Q_D(const Q3DSWidget); @@ -83,12 +112,30 @@ QString Q3DSWidget::error() const return d->error; } +/*! + \property Q3DSWidget::running + + The value of this property is \c true when the viewer has been initialized + and the presentation is running. + + This property is read-only. +*/ bool Q3DSWidget::isRunning() const { Q_D(const Q3DSWidget); return d->engine && d->sourceLoaded; } +/*! + \property Q3DSWidget::updateInterval + + Holds the viewer update interval in milliseconds. If the value is negative, + the viewer doesn't update the presentation automatically. + + The default value is 0, meaning automatic updates are enabled. + + \sa QWidget::update() +*/ int Q3DSWidget::updateInterval() const { Q_D(const Q3DSWidget); diff --git a/src/runtime/behaviorapi/q3dsbehaviorobject.cpp b/src/runtime/behaviorapi/q3dsbehaviorobject.cpp index 75ac946..9a31ce8 100644 --- a/src/runtime/behaviorapi/q3dsbehaviorobject.cpp +++ b/src/runtime/behaviorapi/q3dsbehaviorobject.cpp @@ -265,4 +265,170 @@ void Q3DSBehaviorObject::setDataInputValue(const QString &name, const QVariant & m_engine->setDataInputValue(name, value); } +/*! + \qmltype Behavior + \inqmlmodule QtStudio3D + \ingroup 3dstudioruntime2 + + \brief Technology Preview Behavior Integration + + This is a technology preview (API may change in upcoming version) of how + Qt 3D Studio could support writing custom behavior scripts using QML and + JavaScript. It enables interacting with the runtime using the Behavior + QML class exposed to each behavior script. + + In QML behavior script, the integration to Qt 3D Studio is established by using + the metadata tag system similar to the \l {file-formats-effects.html}{effect} + and \l {file-formats-material.html}{material} files. + + \badcode +[[ +<Property name="somePropertyName" ... /> + +<Handler name="someHandlerName" ... /> + +<Event name="onSomeEvent" ... /> +... +]] + \endcode + + Secondly, the QML behavior script needs access to the QML module. + \badcode +import QtStudio3D.Behavior 2.0 + \endcode + + Finally, the Behavior type needs to be implemented in the qml script. + \badcode +Behavior { + id: mybehavior + + function onInitialize() { + ... + } + + function onActivate() { + ... + } + + function onUpdate() { + ... + } + + function onDeactivate() { + ... + } + + function someHandlerName() { + ... + fireEvent("onSomeEvent") + } +} + \endcode +*/ + +/*! + \qmlmethod float Behavior::getDeltaTime() + + Returns the delta time between this and previous frame in milliseconds. +*/ + +/*! + \qmlmethod var Behavior::getAttribute(string attribute) + + Returns the value of the given \a attribute. +*/ + +/*! + \qmlmethod var Behavior::getAttribute(string handle, string attribute) + + Returns the value of the given \a attribute for a given \a handle. +*/ + +/*! + \qmlmethod void Behavior::setAttribute(string attribute, var value) + + Sets the \a value of the given \a attribute. +*/ + +/*! + \qmlmethod void Behavior::setAttribute(string handle, string attribute, var value) + + Sets the \a value of the given \a attribute for a given \a handle. +*/ + +/*! + \qmlmethod void Behavior::fireEvent(string event) + + Fires the given \a event. +*/ + +/*! + \qmlmethod void Behavior::registerForEvent(string event, QJSValue function) + + Registers the script for an \a event with the handler \a function. +*/ + +/*! + \qmlmethod void Behavior::registerForEvent(string handle, string event, QJSValue function) + + Registers the script for an \a event with the handler \a function for a given \a handle. +*/ + +/*! + \qmlmethod void Behavior::unregisterForEvent(string event) + + Unregisters the script from an \a event. +*/ + +/*! + \qmlmethod void Behavior::unregisterForEvent(string handle, string event) + + Unregisters the script from an \a event for a given \a handle. +*/ + +/*! + \qmlmethod void Behavior::setDataInputValue(string name, variant value) + + Sets the \a value of the data input identified with the \a name. + */ + +/*! + \qmlsignal void Behavior::onInitialize() + + This signal is emitted when the script becomes active the first time. + If multiple behaviors match this, the signal for parent elements will + occur before their children/descendants. \note Each behavior will + only have its \c{onInitialize} signaled once, even if it is deactivated and + later reactivated. + */ + +/*! + \qmlsignal void Behavior::onActivate() + + This signal is emitted when the script becomes active. + Any behaviors which were not active last frame that are active + this frame will have their \c{onActivate} signaled. If + multiple behaviors match this, the signal for parent elements will + occur before their descendants. + */ + +/*! + \qmlsignal void Behavior::onDeactivate() + + This signal is emitted when the script becomes inactive. + Any behaviors which were active last frame that are not active + this frame will have their \c{onDeactivate} signaled. If + multiple behaviors match this, the signal for parent elements will + occur before their descendants. + */ + +/*! + \qmlsignal void Behavior::onUpdate() + + This signal is emitted on each frame when the script is active. + Any behaviors that are active this frame will have their + \c{onUpdate} signaled. If multiple behaviors match this, the signal + for parent elements will occur before their descendants. + */ + QT_END_NAMESPACE diff --git a/src/runtime/doc/doc.pri b/src/runtime/doc/doc.pri new file mode 100644 index 0000000..6c5dd55 --- /dev/null +++ b/src/runtime/doc/doc.pri @@ -0,0 +1,6 @@ +build_online_docs: \ + QMAKE_DOCS = $$PWD/online/qt3dstudioruntime2.qdocconf +else: \ + QMAKE_DOCS = $$PWD/qt3dstudioruntime2.qdocconf + +OTHER_FILES += $$PWD/src/*.qdoc diff --git a/src/doc/online/Qt3DStudioRuntime2.qdocconf b/src/runtime/doc/online/qt3dstudioruntime2.qdocconf index 4602372..4602372 100644 --- a/src/doc/online/Qt3DStudioRuntime2.qdocconf +++ b/src/runtime/doc/online/qt3dstudioruntime2.qdocconf diff --git a/src/runtime/doc/qt3d-runtime-project.qdocconf b/src/runtime/doc/qt3d-runtime-project.qdocconf new file mode 100644 index 0000000..5cf0998 --- /dev/null +++ b/src/runtime/doc/qt3d-runtime-project.qdocconf @@ -0,0 +1,61 @@ +project = Qt3DStudioRuntime2 +description = Qt 3D Studio Runtime Reference Manual +version = 2.0 + +# url is relative to the parent project +url = runtime + +sourcedirs += ./src +imagedirs += ./src/images + +sourcedirs += ../api +headerdirs += ../api + +sourcedirs += ../../imports/studio3d +headerdirs += ../../imports/studio3d + +sourcedirs += ../behaviorapi +headerdirs += ../behaviorapi + +depends = qtcore qtgui qtwidgets qtqml qtquick qtdoc qt3dcore qt3drender qt3dlogic qt3danimation + +qhp.projects = Qt3DStudioRuntime2 + +qhp.Qt3DStudioRuntime2.file = qt3dstudioruntime2.qhp +qhp.Qt3DStudioRuntime2.namespace = io.qt.qt3dstudioruntime2.20 +qhp.Qt3DStudioRuntime2.virtualFolder = qt3dstudioruntime2 +qhp.Qt3DStudioRuntime2.indexTitle = Qt 3D Studio Runtime +qhp.Qt3DStudioRuntime2.indexRoot = + +qhp.Qt3DStudioRuntime2.filterAttributes = qt3dstudioruntime2 2.0 +qhp.Qt3DStudioRuntime2.customFilters.Qt.name = Qt3DStudioRuntime2 2.0 +qhp.Qt3DStudioRuntime2.customFilters.Qt.filterAttributes = qt3dstudioruntime2 2.0 + +qhp.Qt3DStudioRuntime2.subprojects = manual qmltypes classes + +qhp.Qt3DStudioRuntime2.subprojects.manual.title = Qt 3D Studio Runtime +qhp.Qt3DStudioRuntime2.subprojects.manual.indexTitle = Qt 3D Studio Runtime TOC +qhp.Qt3DStudioRuntime2.subprojects.manual.type = manual + +qhp.Qt3DStudioRuntime2.subprojects.qmltypes.title = QML Types +qhp.Qt3DStudioRuntime2.subprojects.qmltypes.indexTitle = Qt 3D Studio Runtime QML Types +qhp.Qt3DStudioRuntime2.subprojects.qmltypes.selectors = qmltype +qhp.Qt3DStudioRuntime2.subprojects.qmltypes.sortPages = true + +qhp.Qt3DStudioRuntime2.subprojects.classes.title = C++ Classes +qhp.Qt3DStudioRuntime2.subprojects.classes.indexTitle = Qt 3D Studio Runtime C++ Classes +qhp.Qt3DStudioRuntime2.subprojects.classes.selectors = class fake:headerfile +qhp.Qt3DStudioRuntime2.subprojects.classes.sortPages = true + +# Add an .html file with sidebar content, used in the online style +HTML.stylesheets += style/qt5-sidebar.html + +navigation.homepage = Qt 3D Studio Runtime +navigation.cppclassespage = Qt 3D Studio Runtime C++ Classes +navigation.qmltypespage = Qt 3D Studio Runtime QML Types +buildversion = "Qt 3D Studio Runtime 2.0 Manual" + +examplesinstallpath = 3dstudioruntime2 +exampledirs += ../../../examples/3dstudioruntime2 + +Cpp.ignoretokens += Q3DSV_EXPORT diff --git a/src/doc/Qt3DStudioRuntime2.qdocconf b/src/runtime/doc/qt3dstudioruntime2.qdocconf index 6f5f526..6f5f526 100644 --- a/src/doc/Qt3DStudioRuntime2.qdocconf +++ b/src/runtime/doc/qt3dstudioruntime2.qdocconf diff --git a/src/runtime/doc/src/attributenames.html b/src/runtime/doc/src/attributenames.html new file mode 100644 index 0000000..422c617 --- /dev/null +++ b/src/runtime/doc/src/attributenames.html @@ -0,0 +1,911 @@ +\raw HTML +<table id='scripting-attributes'> +<tbody></tbody> +<tr><th colspan="4">Scenes</td></tr> +<tr> +<td class='formal'>Name</td> +<td class='scripting'>name</td> +<td class='type'>string</td> +</tr> +<tr> +<td class='formal'>Enable Background Color</td> +<td class='scripting'>bgcolorenable</td> +<td class='type'>boolean</td> +</tr> +<tr> +<td class='formal'>Background Color R</td> +<td class='scripting'>backgroundcolor.r</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Background Color G</td> +<td class='scripting'>backgroundcolor.g</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Background Color B</td> +<td class='scripting'>backgroundcolor.b</td> +<td class='type'>number</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Elements other than Scenes</td></tr> +<tr> +<td class='formal'>Element Name</td> +<td class='scripting'>name</td> +<td class='type'>string</td> +</tr> +<tr> +<td class='formal'>(Eyeball)</td> +<td class='scripting'>eyeball</td> +<td class='type'>boolean</td> +</tr> +<tr> +<td class='formal'>Timebar Start</td> +<td class='scripting'>starttime</td> +<td class='type'>number</td> +<td class='note'> +in integer milliseconds +</td> +</tr> +<tr> +<td class='formal'>Timebar End</td> +<td class='scripting'>endtime</td> +<td class='type'>number</td> +<td class='note'> +in integer milliseconds +</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Layers</td></tr> +<tr> +<td class='formal'>Disable Depth Test</td> +<td class='scripting'>disabledepthtest</td> +<td class='type'>boolean</td> +</tr> +<tr> +<td class='formal'>Progressive AA</td> +<td class='scripting'>progressiveaa</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'None'</code>, <code>'2x'</code>, <code>'4x'</code>, <code>'8x'</code> +</td> +</tr> +<tr> +<td class='formal'>Multisample AA</td> +<td class='scripting'>multisampleaa</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'None'</code>, <code>'2x'</code>, <code>'4x'</code> +</td> +</tr> +<tr> +<td class='formal'>Temporal AA</td> +<td class='scripting'>temporalaa</td> +<td class='type'>boolean</td> +</tr> +<tr> +<td class='formal'>Layer Background</td> +<td class='scripting'>background</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Transparent'</code>, <code>'Unspecified'</code>, <code>'SolidColor'</code> +</td> +</tr> +<tr> +<td class='formal'>Background Color R</td> +<td class='scripting'>backgroundcolor.r</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Background Color G</td> +<td class='scripting'>backgroundcolor.g</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Background Color B</td> +<td class='scripting'>backgroundcolor.b</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Blend Type</td> +<td class='scripting'>blendtype</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Normal'</code>, <code>'Screen'</code>, <code>'Multiply'</code>, <code>'Add'</code>, <code>'*Overlay'</code>, <code>'*ColorBurn'</code>, <code>'*ColorDodge'</code> +</td> +</tr> +<tr> +<td class='formal'>Horizontal Fields</td> +<td class='scripting'>horzfields</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Left/Width'</code>, <code>'Left/Right'</code>, <code>'Width/Right'</code> +</td> +</tr> +<tr> +<td class='formal'>Left</td> +<td class='scripting'>left</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Left Units</td> +<td class='scripting'>leftunits</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'pixels'</code>, <code>'percent'</code> +</td> +</tr> +<tr> +<td class='formal'>Width</td> +<td class='scripting'>width</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Width Units</td> +<td class='scripting'>widthunits</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'pixels'</code>, <code>'percent'</code> +</td> +</tr> +<tr> +<td class='formal'>Right</td> +<td class='scripting'>right</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Right Units</td> +<td class='scripting'>rightunits</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'pixels'</code>, <code>'percent'</code> +</td> +</tr> +<tr> +<td class='formal'>Vertical Fields</td> +<td class='scripting'>vertfields</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Top/Height'</code>, <code>'Top/Bottom'</code>, <code>'Height/Bottom'</code> +</td> +</tr> +<tr> +<td class='formal'>Top</td> +<td class='scripting'>top</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Top Units</td> +<td class='scripting'>topunits</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'pixels'</code>, <code>'percent'</code> +</td> +</tr> +<tr> +<td class='formal'>Height</td> +<td class='scripting'>height</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Height Units</td> +<td class='scripting'>heightunits</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'pixels'</code>, <code>'percent'</code> +</td> +</tr> +<tr> +<td class='formal'>Bottom</td> +<td class='scripting'>bottom</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Bottom Units</td> +<td class='scripting'>bottomunits</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'pixels'</code>, <code>'percent'</code> +</td> +</tr> +<tr> +<td class='formal'>Ambient Occlusion</td> +<td class='scripting'>aostrength</td> +<td class='type'>number</td> +<td class='note'> +values between 0 and 100 +</td> +</tr> +<tr> +<td class='formal'>AO Distance</td> +<td class='scripting'>aodistance</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>AO Softness</td> +<td class='scripting'>aosoftness</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>AO Threshold</td> +<td class='scripting'>aobias</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>AO Sampling Rate</td> +<td class='scripting'>aosamplerate</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>AO Dithering</td> +<td class='scripting'>aodither</td> +<td class='type'>boolean</td> +</tr> +<tr> +<td class='formal'>Shadow Strength</td> +<td class='scripting'>shadowstrength</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Shadow Distance</td> +<td class='scripting'>shadowdist</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Shadow Softness</td> +<td class='scripting'>shadowsoftness</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Shadow Threshold</td> +<td class='scripting'>shadowbias</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Light Probe</td> +<td class='scripting'>lightprobe</td> +<td class='type'>image element</td> +</tr> +<tr> +<td class='formal'>IBL Horizon Cutoff</td> +<td class='scripting'>probehorizon</td> +<td class='type'>number</td> +<td class='note'> +values from -1 (no horizon) to -0.001 (hard edge) +</td> +</tr> +<tr> +<td class='formal'>Sub-Presentation</td> +<td class='scripting'>sourcepath</td> +<td class='type'>string</td> +<td class='note'> +id of the sub-presentation to display +</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Nodes</td></tr> +<tr> +<td class='formal'>Position X</td> +<td class='scripting'>position.x</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Position Y</td> +<td class='scripting'>position.y</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Position Z</td> +<td class='scripting'>position.z</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Rotation X</td> +<td class='scripting'>rotation.x</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Rotation Y</td> +<td class='scripting'>rotation.y</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Rotation Z</td> +<td class='scripting'>rotation.z</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Scale X</td> +<td class='scripting'>scale.x</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Scale Y</td> +<td class='scripting'>scale.y</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Scale Z</td> +<td class='scripting'>scale.z</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Pivot X</td> +<td class='scripting'>pivot.x</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Pivot Y</td> +<td class='scripting'>pivot.y</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Pivot Z</td> +<td class='scripting'>pivot.z</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Opacity</td> +<td class='scripting'>opacity</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'></td> +<td class='scripting'>orientation</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Left Handed'</code>, <code>'Right Handed'</code> +</td> +</tr> +<tr> +<td class='formal'></td> +<td class='scripting'>rotationorder</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'XYZ'</code>, <code>'YZX'</code>, <code>'ZXY'</code>, <code>'XZY'</code>, <code>'YXZ'</code>, <code>'ZYX'</code>, <code>'XYZr'</code>, <code>'YZXr'</code>, <code>'ZXYr'</code>, <code>'XZYr'</code>, <code>'YXZr'</code>, <code>'ZYXr'</code> +</td> +</tr> +<tr> +<td class='formal'></td> +<td class='scripting'>ignoresparent</td> +<td class='type'>boolean</td> +<td class='note'> +prevents parent transformation from being applied [ignored as of 2.0] +</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Aliases</td></tr> +<tr> +<td class='formal'>Reference</td> +<td class='scripting'>referencednode</td> +<td class='type'>string</td> +<td class='note'> +relative or absolute element path +</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Cameras</td></tr> +<tr> +<td class='formal'>Orthographic</td> +<td class='scripting'>orthographic</td> +<td class='type'>boolean</td> +</tr> +<tr> +<td class='formal'>Field of View</td> +<td class='scripting'>fov</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Clipping Start</td> +<td class='scripting'>clipnear</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Clipping End</td> +<td class='scripting'>clipfar</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Runtime Scale Mode</td> +<td class='scripting'>scalemode</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Fit'</code>, <code>'Same Size'</code> +</td> +</tr> +<tr> +<td class='formal'>Runtime Scale Anchor</td> +<td class='scripting'>scaleanchor</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Center'</code>, <code>'NW'</code>, <code>'N'</code>, <code>'NE'</code>, <code>'E'</code>, <code>'SE'</code>, <code>'S'</code>, <code>'SW'</code>, <code>'W'</code> +</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Lights</td></tr> +<tr> +<td class='formal'>Scope</td> +<td class='scripting'>scope</td> +<td class='type'>string</td> +<td class='note'> +full path to the element +</td> +</tr> +<tr> +<td class='formal'>Light Type</td> +<td class='scripting'>lighttype</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Directional'</code>, <code>'Point'</code>, <code>'Area'</code> +</td> +</tr> +<tr> +<td class='formal'>Light Color R</td> +<td class='scripting'>lightdiffuse.r</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Light Color G</td> +<td class='scripting'>lightdiffuse.g</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Light Color B</td> +<td class='scripting'>lightdiffuse.b</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Specular Color R</td> +<td class='scripting'>lightspecular.r</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Specular Color G</td> +<td class='scripting'>lightspecular.g</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Specular Color B</td> +<td class='scripting'>lightspecular.b</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Ambient Color R</td> +<td class='scripting'>lightambient.r</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Ambient Color G</td> +<td class='scripting'>lightambient.g</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Ambient Color B</td> +<td class='scripting'>lightambient.b</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Brightness</td> +<td class='scripting'>brightness</td> +<td class='type'>number</td> +<td class='note'> +only applies to point lights +</td> +</tr> +<tr> +<td class='formal'>Linear Fade</td> +<td class='scripting'>linearfade</td> +<td class='type'>number</td> +<td class='note'> +only applies to point lights +</td> +</tr> +<tr> +<td class='formal'>Exponential Fade</td> +<td class='scripting'>expfade</td> +<td class='type'>number</td> +<td class='note'> +only applies to point lights +</td> +</tr> +<tr> +<td class='formal'>Cast Shadows?</td> +<td class='scripting'>castshadow</td> +<td class='type'>boolean</td> +</tr> +<tr> +<td class='formal'>Shadow Darkness</td> +<td class='scripting'>shdwfactor</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Shadow Softness</td> +<td class='scripting'>shdwfilter</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Shadow Resolution</td> +<td class='scripting'>shdwmapres</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'256'</code>, <code>'512'</code>, <code>'1024'</code>, <code>'2048'</code> +</td> +</tr> +<tr> +<td class='formal'>Shadow Depth Bias</td> +<td class='scripting'>shdwbias</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Shadow Far Clip</td> +<td class='scripting'>shdwmapfar</td> +<td class='type'>number</td> +<tr> +<td class='formal'>Shadow Field of View</td> +<td class='scripting'>shdwmapfov</td> +<td class='type'>number</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Groups</td></tr> +<tr> +<td class='formal'>Import</td> +<td class='scripting'>sourcepath</td> +<td class='type'>string</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Text</td></tr> +<tr> +<td class='formal'>Text String</td> +<td class='scripting'>textstring</td> +<td class='type'>string</td> +</tr> +<tr> +<td class='formal'>Text Color R</td> +<td class='scripting'>textcolor.r</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Text Color G</td> +<td class='scripting'>textcolor.g</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Text Color B</td> +<td class='scripting'>textcolor.b</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Font</td> +<td class='scripting'>font</td> +<td class='type'>string</td> +</tr> +<tr> +<td class='formal'>Font Size</td> +<td class='scripting'>size</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Horizontal Alignment</td> +<td class='scripting'>horzalign</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Left'</code>, <code>'Center'</code>, <code>'Right'</code> +</td> +</tr> +<tr> +<td class='formal'>Vertical Alignment</td> +<td class='scripting'>vertalign</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Top'</code>, <code>'Middle'</code>, <code>'Bottom'</code> +</td> +</tr> +<tr> +<td class='formal'>Leading</td> +<td class='scripting'>leading</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Tracking</td> +<td class='scripting'>tracking</td> +<td class='type'>number</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Models</td></tr> +<tr> +<td class='formal'>Mesh</td> +<td class='scripting'>sourcepath</td> +<td class='type'>string</td> +</tr> +<tr> +<td class='formal'>Tessellation Mode</td> +<td class='scripting'>tessellation</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'None'</code>, <code>'Linear'</code>, <code>'Phong'</code>, <code>'NPatch'</code> [ignored as of 2.0] +</td> +</tr> +<tr> +<td class='formal'>Edge Tessellation Value</td> +<td class='scripting'>edgetess</td> +<td class='type'>number</td> +<td class='note'> +[ignored as of 2.0] +</td> +</tr> +<tr> +<td class='formal'>Inner Tessellation Value</td> +<td class='scripting'>innertess</td> +<td class='type'>number</td> +<td class='note'> +[ignored as of 2.0] +</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Standard Materials</td></tr> +<tr> +<td class='formal'>Lighting</td> +<td class='scripting'>shaderlighting</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Vertex'</code>, <code>'Pixel'</code>, <code>'None'</code> +</td> +</tr> +<tr> +<td class='formal'>Blending Mode</td> +<td class='scripting'>blendmode</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Normal'</code>, <code>'Screen'</code>, <code>'Multiply'</code> +</td> +</tr> +<tr> +<td class='formal'>Diffuse Color R</td> +<td class='scripting'>diffuse.r</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Diffuse Color G</td> +<td class='scripting'>diffuse.g</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Diffuse Color B</td> +<td class='scripting'>diffuse.b</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Diffuse Map</td> +<td class='scripting'>diffusemap</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tr> +<td class='formal'>Diffuse Map 2</td> +<td class='scripting'>diffusemap2</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tr> +<td class='formal'>Diffuse Map 3</td> +<td class='scripting'>diffusemap3</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tr> +<td class='formal'>Specular Reflection</td> +<td class='scripting'>specularreflection</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tr> +<td class='formal'>Specular Tint R</td> +<td class='scripting'>speculartint.r</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Specular Tint G</td> +<td class='scripting'>speculartint.g</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Specular Tint B</td> +<td class='scripting'>speculartint.b</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Specular Amount</td> +<td class='scripting'>specularamount</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Specular Map</td> +<td class='scripting'>specularmap</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tr> +<td class='formal'>Specular Model</td> +<td class='scripting'>specularmodel</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Default'</code>, <code>'KGGX'</code>, <code>'KWard'</code> +</td> +</tr> +<tr> +<td class='formal'>Fresnel Power</td> +<td class='scripting'>fresnelPower</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Index of Refraction</td> +<td class='scripting'>ior</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Specular Roughness</td> +<td class='scripting'>specularroughness</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Bump Map</td> +<td class='scripting'>bumpmap</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tr> +<td class='formal'>Normal Map</td> +<td class='scripting'>normalmap</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tr> +<td class='formal'>Bump Amount</td> +<td class='scripting'>bumpamount</td> +<td class='type'>number</td> +<td class='note'> +affects both bump and normal maps +</td> +</tr> +<tr> +<td class='formal'>Displacement Map</td> +<td class='scripting'>displacementmap</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tr> +<td class='formal'>Displacement Amount</td> +<td class='scripting'>displaceamount</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Opacity</td> +<td class='scripting'>opacity</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Opacity Map</td> +<td class='scripting'>opacitymap</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tr> +<td class='formal'>Emissive Power</td> +<td class='scripting'>emissivepower</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Emissive Map</td> +<td class='scripting'>emissivemap</td> +<td class='type'>image element</td> +<td class='note'> +to change the image set the <code>sourcepath</code> attribute on the image element +</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Material References</td></tr> +<tr> +<td class='formal'>Referenced Material</td> +<td class='scripting'>referencedmaterial</td> +<td class='type'>string</td> +<td class='note'> +relative or absolute element path +</td> +</tr> +<tbody></tbody> +<tr><th colspan="4">Images</td></tr> +<tr> +<td class='formal'>U Repeat</td> +<td class='scripting'>scaleu</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>V Repeat</td> +<td class='scripting'>scalev</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Texture Mapping</td> +<td class='scripting'>mappingmode</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'UV Mapping'</code>, <code>'Environmental Mapping'</code> +</td> +</tr> +<tr> +<td class='formal'>U Tiling</td> +<td class='scripting'>tilingmodehorz</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Tiled'</code>, <code>'Mirrored'</code>, <code>'No Tiling'</code> +</td> +</tr> +<tr> +<td class='formal'>V Tiling</td> +<td class='scripting'>tilingmodevert</td> +<td class='type'>string</td> +<td class='note'> +values: <code>'Tiled'</code>, <code>'Mirrored'</code>, <code>'No Tiling'</code> +</td> +</tr> +<tr> +<td class='formal'>UV Rotation</td> +<td class='scripting'>rotationuv</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>U Position</td> +<td class='scripting'>positionu</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>V Position</td> +<td class='scripting'>positionv</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>U Pivot</td> +<td class='scripting'>pivotu</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>V Pivot</td> +<td class='scripting'>pivotv</td> +<td class='type'>number</td> +</tr> +<tr> +<td class='formal'>Sub-Presentation</td> +<td class='scripting'>subpresentation</td> +<td class='type'>string</td> +<td class='note'> +id of the sub-presentation to display +</td> +</tr> +<tr> +<td class='formal'>Source Path</td> +<td class='scripting'>sourcepath</td> +<td class='type'>string</td> +<td class='note'> +path to the image +</td> +</tr> +</table> +\endraw diff --git a/src/runtime/doc/src/attributenames.qdoc b/src/runtime/doc/src/attributenames.qdoc new file mode 100644 index 0000000..18282de --- /dev/null +++ b/src/runtime/doc/src/attributenames.qdoc @@ -0,0 +1,71 @@ +!/**************************************************************************** +** +** Copyright (C) 1993-2009 NVIDIA Corporation. +** 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$ +** +****************************************************************************/ + +// Pull in attributenames.html into qdoc. Note that attributenames.html is +// manually maintained since 2.0 and is not auto-generated. + +/*! + \page qt3d-runtime-attribute-names.html + \title Attribute Names + \keyword Attributes + + Below is a list of the attributes that can be set on the various scene + objects via Q3DSPresentation::setAttribute() or Q3DSElement::setAttribute(). + + \note vector (e.g. a group's or model's \c rotation) and color (e.g. a + material's \c diffuse) attributes allow setting/getting all components in + one operation, and are mapped to QVector3D and QColor, respectively. + + \note As of Qt 3D Studio 2.0 not all properties can be changed on the fly at + run time. As a general rule attributes that are animatable in the Qt 3D + Studio application are freely changeable by the applications during run time + as well. + + \note When possible, applications are recommended to rely on the \c{data + input} functionality of Qt 3D Studio instead. This avoids the need to refer + to hard-coded attribute names, and instead allows the designers to expose + the interesting attributes with arbitrary data input names to the + application developers, thus offering a fixed, well-known interface from the + 3D presentation to the application code. See \l Q3DSDataInput and + \l DataInput for more information. + + \include attributenames.html + + Custom materials and effects have their custom set of properties that are + defined in the \c{.material} or \c{.effect} file. For example, an instances + of an effect with the following metadata will have an attribute \c HBlurBias + with the type \c number that can be set and queried as if it was a built-in + attribute. + + \badcode + <Effect> + <MetaData> + <Property name="HBlurBias" formalName="Horizontal Blur" min="0" max="10" default="2" description="Amount of corona horizontally."/> + ... + \endcode +*/ diff --git a/src/doc/src/copyright.qdoc b/src/runtime/doc/src/copyright.qdoc index 01275f1..01275f1 100644 --- a/src/doc/src/copyright.qdoc +++ b/src/runtime/doc/src/copyright.qdoc diff --git a/src/doc/src/embedded.qdoc b/src/runtime/doc/src/embedded.qdoc index f665582..095a46d 100644 --- a/src/doc/src/embedded.qdoc +++ b/src/runtime/doc/src/embedded.qdoc @@ -29,5 +29,4 @@ \page qt3d-runtime-embedded.html \title Using the Runtime on Embedded Devices - embedded stuff (eglfs etc.) */ diff --git a/src/doc/src/examples.qdoc b/src/runtime/doc/src/examples.qdoc index 86cab63..3d70a2c 100644 --- a/src/doc/src/examples.qdoc +++ b/src/runtime/doc/src/examples.qdoc @@ -33,4 +33,25 @@ Included in Qt 3D Studio Runtime you will find a set of examples. These are located in the \c {examples} folder in the installation folder. + + \section1 QML Examples + + \list + \li \l {Qt 3D Studio Runtime: Simple QML Example} + \li \l {Qt 3D Studio Runtime: QML DataInput Example} + \endlist + + \section1 C++ Examples + + \list + \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} + \endlist + + \section1 More Examples + + You can find more examples from + \l{https://git.qt.io/public-demos/qt3dstudio}, these examples are more + visually appealing and suitable to use as demos for example. */ diff --git a/src/runtime/doc/src/gettingstarted.qdoc b/src/runtime/doc/src/gettingstarted.qdoc new file mode 100644 index 0000000..a0cef3f --- /dev/null +++ b/src/runtime/doc/src/gettingstarted.qdoc @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** 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-gettingstarted.html + \title Getting Started + + The Qt 3D Studio Runtime provides C++ and QML APIs for integrating Qt 3D + Studio scenes into Qt applications, as well as the viewer application that + is used in combination with the Qt 3D Studio application during the design + phase. + + Below is an example scene in the Qt 3D Studio application. + + \image intro-editor.png + + During the design phase, the standalone viewer is typically launched from + the editor several times to check and verify the presentation in the + runtime. + + \image intro-viewer.png + + Once the design is done and the \c{.uia}, \c{.uip}, and other asset files + are available, these can be loaded, rendered, and manipulated in Qt + applications. This is done via the APIs provided in the \c 3dstudioruntime2 + module and the \c QtStudio3D QML plugin. + + Below is the same scene loaded into a simple Qt Quick application + (the \l{Qt 3D Studio Runtime: Simple QML Example}{simpleqml + example}) that composes the 3D content with the other Qt Quick + items, for example the ones provided by \l{Qt Quick Controls + 2}. In addition to displaying the presentation, the application + can also control many aspects of it (slides, timeline, object + properties) and can react on certain conditions, such as when a 3D + object is clicked on (picked) by mouse or touch input. + + \image intro-app.png + + To profile, debug, and tune the presentation, the runtime provides a + built-in, in-scene debug pane that can be toggled both from the viewer and, + optionally, from applications as well. + + \image intro-viewer-profile.png + + \section1 Rendering Scenes + + APIs are provided for the following Qt UI technologies: + + \list + + \li Qt Quick: here applications import QtStudio3D 2.0 which provides the + \l Studio3D QML type, a Qt Quick item that can be added to Qt Quick scenes. + Under the hood this is similar to adding a \l Scene3D (when working + directly with the lower level Qt 3D framework) or a custom item based on + \l QQuickFramebufferObject into the scene. + + \li Widgets: Q3DSWidget is a QOpenGLWidget subclass that displays Qt 3D + Studio scenes. + + \li QWindow or offscreen render targets (OpenGL texture): Q3DSSurfaceViewer + can be used both to render to an on-screen QWindow, as well as off-screen + into an OpenGL texture. The latter allows reading back and saving the + frames, to generate pre-rendered video sequences for example. + + \endlist + + \section1 Manipulating Scenes + + Rendering Qt 3D Studio scenes is only part of the story since many scenes + are not static and will not just display all their contents as they were + done by designers in the Qt 3D Studio application. Rather, properties of + scene objects (for example, the rotation property of a 3D model, or the + diffuse color of the material associated with such a model) may need to be + changed dynamically, at run time. The timeline or the current slide may + also need to be adjusted based on the user's actions or other application + state. + + As of Qt 3D Studio 2.0 such functionality is exposed via the + Q3DSPresentation (\l Presentation), Q3DSElement (\l Element), + Q3DSSceneElement (\l SceneElement), and Q3DSDataInput (\l DataInput) + objects. Advanced scene manipulation (for instance dynamically spawning and + removing objects in the 3D scene) will be introduced in future versions. +*/ diff --git a/src/runtime/doc/src/images/intro-app.png b/src/runtime/doc/src/images/intro-app.png Binary files differnew file mode 100644 index 0000000..3658190 --- /dev/null +++ b/src/runtime/doc/src/images/intro-app.png diff --git a/src/runtime/doc/src/images/intro-editor.png b/src/runtime/doc/src/images/intro-editor.png Binary files differnew file mode 100644 index 0000000..52e5a69 --- /dev/null +++ b/src/runtime/doc/src/images/intro-editor.png diff --git a/src/runtime/doc/src/images/intro-viewer-profile.png b/src/runtime/doc/src/images/intro-viewer-profile.png Binary files differnew file mode 100644 index 0000000..24d23ad --- /dev/null +++ b/src/runtime/doc/src/images/intro-viewer-profile.png diff --git a/src/runtime/doc/src/images/intro-viewer.png b/src/runtime/doc/src/images/intro-viewer.png Binary files differnew file mode 100644 index 0000000..f36d57b --- /dev/null +++ b/src/runtime/doc/src/images/intro-viewer.png diff --git a/src/doc/src/index.qdoc b/src/runtime/doc/src/index.qdoc index a2c5282..43d8b18 100644 --- a/src/doc/src/index.qdoc +++ b/src/runtime/doc/src/index.qdoc @@ -26,22 +26,21 @@ ****************************************************************************/ /*! -\keyword Qt 3D Studio Runtime -\title Qt 3D Studio Runtime Index -\page index.html +\title Qt 3D Studio Runtime +\page qt3d-runtime-index.html \section1 Table of Contents \list \li \l {Getting Started} - \li \l {Qt 3D Studio Runtime C++ Classes} - \li \l {Qt 3D Studio Runtime QML Types} + \li \l {System and Application Requirements} \li \l {Using the Runtime on Android/iOS Devices} \li \l {Using the Runtime on Embedded Devices} + \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 {Examples} \li \l {Copyright Notices} \endlist -blah blah blah - */ diff --git a/src/doc/src/mobile.qdoc b/src/runtime/doc/src/mobile.qdoc index 1787b63..45fd6a0 100644 --- a/src/doc/src/mobile.qdoc +++ b/src/runtime/doc/src/mobile.qdoc @@ -29,5 +29,4 @@ \page qt3d-runtime-mobile.html \title Using the Runtime on Android/iOS Devices - mobile stuff */ diff --git a/src/doc/src/module.qdoc b/src/runtime/doc/src/module.qdoc index d37417f..d37417f 100644 --- a/src/doc/src/module.qdoc +++ b/src/runtime/doc/src/module.qdoc diff --git a/src/runtime/doc/src/requirements.qdoc b/src/runtime/doc/src/requirements.qdoc new file mode 100644 index 0000000..1bec57e --- /dev/null +++ b/src/runtime/doc/src/requirements.qdoc @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** 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-requirements.html + \title System and Application Requirements + + \section1 OpenGL Requirements + + Qt 3D Studio requires OpenGL or OpenGL ES. The recommended minimum versions + are \c{3.3 core profile} and \c{3.0}, respectively. + + When it comes to OpenGL ES, a limited subset of the functionality is + available when running on plain \c{OpenGL ES 2.0} implementations. In + practice this means losing shadow mapping, image based lighting, and many + other advanced features and is therefore not recommended. On the other hand, + this allows bringing up Qt 3D Studio scenes on boards like the Raspberry Pi + (with the original proprietary graphics stack) or the Beaglebone Black, or + in hypervisor-based virtualized environments where the GPU virtualization + only supports GLES 2.0, and can therefore still be valuable in certain + special situations. + + Non-native implementations, like \c ANGLE or software implementations like + \c{Mesa's llvmpipe} may work but are not tested and can fail in unexpected + ways. + + As of version 2.0 the Qt 3D Studio Runtime is implemented on top of Qt + 3D. This means that most graphics API and windowing system bits are + abstracted and hidden from the runtime. However, there are still direct + OpenGL dependencies in a few places and, more importantly, the standard + material, custom materials, and effects all rely on GLSL. Therefore other + graphics APIs, such as, Vulkan or Direct 3D, cannot be supported at this + time. + + \section1 Application Integration Notes + + \section2 C++ + + A typical Qt C++ application using the Qt 3D Studio Runtime is expected to + query and honor the runtime's \c{ideal surface format}. This way the OpenGL + contexts will all be created with the OpenGL version and profile that best + match the runtime's needs: + + \badcode + #include <Q3DSWidget> // or <q3dsruntimeglobal.h> if only Q3DS::surfaceFormat() is interesting for main() + + int main(int argc, char *argv[]) + { + QApplication app(argc, argv); + + QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat()); + + Q3DSWidget w; + ... + return app.exec(); + } + \endcode + + To enable using Qt 3D Studio headers and libraries in the application, add + the \c 3dstudioruntime2 module in the application's \c{.pro} file: + + \badcode + QT += 3dstudioruntime2 + \endcode + + \section2 QML/Qt Quick + + When no C++ classes are used, the \c 3dstudioruntime2 module can be omitted + in the \c{.pro}. To use the \l Studio3D element in QML code, it is enough to add the + corresponding import statement: + + \badcode + import QtStudio3D 2.0 + \endcode + + It is nonetheless strongly recommended to set the the default surface format + as shown above. Make sure the + \c{QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat())} call is made + after constructing QGuiApplication but before the first QQuickWindow or + QQuickView. When this is not possible, for example because the QML contents + is hosted in an application that has no knowledge of the Qt Quick scene's 3D + needs, Studio3D may still be usable but this may be dependent on the OpenGL + implementation and the context versions it offers, and is therefore more fragile. +*/ diff --git a/src/doc/src/gettingstarted.qdoc b/src/runtime/doc/src/toc.qdoc index 2f5ae37..9e28102 100644 --- a/src/doc/src/gettingstarted.qdoc +++ b/src/runtime/doc/src/toc.qdoc @@ -26,8 +26,15 @@ ****************************************************************************/ /*! - \page qt3d-runtime-gettingstarted.html - \title Getting Started +\contentspage {Qt 3D Studio Runtime} +\page qt3d-runtime-toc.html +\title Qt 3D Studio Runtime TOC - Basic blah blah +\omit +This file is used for generating a TOC in a .qch file. +\endomit + +\list + \li \l {index.html}{Overview} +\endlist */ diff --git a/src/runtime/doc/style/qt5-sidebar.html b/src/runtime/doc/style/qt5-sidebar.html new file mode 100644 index 0000000..53a2bbe --- /dev/null +++ b/src/runtime/doc/style/qt5-sidebar.html @@ -0,0 +1,28 @@ +<div class="sectionlist normallist"> + <div> + <a name="reference"></a> + <h2 id="reference">Qt 3D Studio Runtime</h2> + </div> + <div class="indexboxcont indexboxbar"> + <ul> + <li><a href="qt3d-runtime-index.html">Home</a></li> + <li><a href="qt3d-runtime-gettingstarted.html">Getting Started</a></li> + <li><a href="qt3d-runtime-qml.html">QML API Reference</a></li> + <li><a href="qt3d-runtime-cpp.html">C++ API Reference</a></li> + <li><a href="qt3d-runtime-attribute-names.html">Scene Object Attributes</a></li> + <li><a href="qt3d-runtime-examples-examples.html">Examples</a></li> + <li><a href="copyright-notices.html">Copyright Notices</a></li> + </ul> + </div> +</div> +<div class="sectionlist normallist"> + <div> + <a name="reference"></a> + <h2 id="reference">Qt 3D Studio</h2> + </div> + <div class="indexboxcont indexboxbar"> + <ul> + <li><a href="../index.html">Home</a></li> + </ul> + </div> +</div> diff --git a/src/runtime/q3dsanimationmanager.cpp b/src/runtime/q3dsanimationmanager.cpp index 474a54d..9c8eadb 100644 --- a/src/runtime/q3dsanimationmanager.cpp +++ b/src/runtime/q3dsanimationmanager.cpp @@ -509,23 +509,28 @@ void Q3DSAnimationManager::updateAnimationHelper(const AnimationTrackListMap<T * class DummyCallback : public Qt3DAnimation::QAnimationCallback { public: - DummyCallback(Q3DSSlide *slide, Q3DSSlidePlayer* slidePlayer) - : m_slide(slide), m_slidePlayer(slidePlayer) {} + DummyCallback(Q3DSSlide *slide) + : m_slide(slide) {} void valueChanged(const QVariant &value) override { Q_ASSERT(m_slide); - Q_ASSERT(m_slidePlayer); + const float newValue = value.toFloat(); + if (qFuzzyCompare(m_previousValue, newValue)) + return; + + Q3DSSlidePlayer *slidePlayer = m_slide->attached<Q3DSSlideAttached>()->slidePlayer; // TODO: See QT3DS-1302 - if (m_slidePlayer != m_slide->attached<Q3DSSlideAttached>()->slidePlayer) + if (!slidePlayer) return; - m_slidePlayer->setSlideTime(m_slide, value.toFloat() * 1000.0f); + slidePlayer->setSlideTime(m_slide, newValue * 1000.0f); + m_previousValue = newValue; } private: Q3DSSlide *m_slide; - Q3DSSlidePlayer *m_slidePlayer; + float m_previousValue = -1.0f; }; void Q3DSAnimationManager::clearAnimations(Q3DSSlide *slide) @@ -613,7 +618,7 @@ void Q3DSAnimationManager::buildClipAnimator(Q3DSSlide *slide) QChannelMapper *mapper = new QChannelMapper; QCallbackMapping *mapping = new QCallbackMapping; mapping->setChannelName(channelName); - mapping->setCallback(QMetaType::Float, new DummyCallback(slide, m_slidePlayer)); + mapping->setCallback(QMetaType::Float, new DummyCallback(slide)); mapper->addMapping(mapping); animator->setChannelMapper(mapper); // TODO: We could just use this to get the time values directly... diff --git a/src/runtime/q3dsanimationmanager_p.h b/src/runtime/q3dsanimationmanager_p.h index 47ec31e..88f1e05 100644 --- a/src/runtime/q3dsanimationmanager_p.h +++ b/src/runtime/q3dsanimationmanager_p.h @@ -50,8 +50,6 @@ QT_BEGIN_NAMESPACE class Q3DSAnimationManager { public: - Q3DSAnimationManager(Q3DSSlidePlayer *slidePlayer) : m_slidePlayer(slidePlayer) {} - void updateAnimations(Q3DSSlide *slide, bool editorMode = false); void clearAnimations(Q3DSSlide *slide); void applyChanges(); @@ -106,7 +104,6 @@ private: QMultiHash<Q3DSGraphObject *, AnimationValueChange> m_changes; - Q3DSSlidePlayer *m_slidePlayer; QSet<Q3DSGraphObject *> m_activeTargets; friend class Q3DSAnimationCallback; diff --git a/src/runtime/q3dsengine.cpp b/src/runtime/q3dsengine.cpp index 30c7a44..5faae2c 100644 --- a/src/runtime/q3dsengine.cpp +++ b/src/runtime/q3dsengine.cpp @@ -90,6 +90,8 @@ static const int MAX_LOG_MESSAGE_LENGTH = 1000; static const int MAX_LOG_LENGTH = 10000; static Q3DSGraphicsLimits gfxLimits; +static bool surfaceFormatAdopted = false; +static QSurfaceFormat adoptedSurfaceFormat; static QMutex q3ds_msg_mutex; static QStringList q3ds_msg_buf; @@ -190,6 +192,25 @@ static void initGraphicsLimits(QOpenGLContext *ctx) gfxLimits.multisampleTextureSupported = QOpenGLTexture::hasFeature(QOpenGLTexture::TextureMultisample); qDebug(" multisample textures: %s", gfxLimits.multisampleTextureSupported ? "true" : "false"); + auto extensions = ctx->extensions(); + if (!extensions.isEmpty()) { + gfxLimits.extensions = extensions; + + if (ctx->isOpenGLES() && ctx->format().majorVersion() == 2) { + gfxLimits.shaderTextureLodSupported = false; + gfxLimits.shaderUniformBufferSupported = false; + gfxLimits.packedDepthStencilBufferSupported = false; + } + if (extensions.contains("GL_EXT_shader_texture_lod")) + gfxLimits.shaderTextureLodSupported = true; + qDebug(" texture lod: %s", gfxLimits.shaderTextureLodSupported ? "true" : "false"); + + if (extensions.contains("GL_EXT_packed_depth_stencil")) + gfxLimits.packedDepthStencilBufferSupported = true; + qDebug(" packed depth-stencil: %s", gfxLimits.packedDepthStencilBufferSupported ? "true" : "false"); + } + qDebug() << " extensions: " << extensions; + // version string bonanza for the profiler const char *rendererStr = reinterpret_cast<const char *>(f->glGetString(GL_RENDERER)); if (rendererStr) { @@ -207,22 +228,6 @@ static void initGraphicsLimits(QOpenGLContext *ctx) qDebug(" version: %s", versionStr); } - auto extensions = ctx->extensions(); - if (!extensions.isEmpty()) { - gfxLimits.extensions = extensions; - qDebug() << " extensions: " << extensions; - - if (ctx->isOpenGLES() && ctx->format().majorVersion() == 2) { - gfxLimits.shaderTextureLodSupported = false; - gfxLimits.shaderUniformBufferSupported = false; - gfxLimits.packedDepthStencilBufferSupported = false; - } - if (extensions.contains("GL_EXT_shader_texture_lod")) - gfxLimits.shaderTextureLodSupported = true; - if (extensions.contains("GL_EXT_packed_depth_stencil")) - gfxLimits.packedDepthStencilBufferSupported = true; - } - gfxLimits.format = ctx->format(); ctx->doneCurrent(); @@ -300,7 +305,7 @@ static QSurfaceFormat findIdealGLESVersion() return fmt; } -QSurfaceFormat Q3DSEngine::surfaceFormat() +static QSurfaceFormat idealSurfaceFormat() { static const QSurfaceFormat f = [] { QSurfaceFormat fmt; @@ -318,14 +323,33 @@ QSurfaceFormat Q3DSEngine::surfaceFormat() } namespace Q3DS { +void adoptSurfaceFormat(const QSurfaceFormat &format) +{ + QSurfaceFormat adjustedFormat = format; + adjustedFormat.setDepthBufferSize(24); + adjustedFormat.setStencilBufferSize(8); + QOpenGLContext ctx; + ctx.setFormat(adjustedFormat); + if (ctx.create()) { + initGraphicsLimits(&ctx); + adoptedSurfaceFormat = adjustedFormat; + surfaceFormatAdopted = true; + } else { + qWarning() << "Failed to create OpenGL context with adopted surface format" << adjustedFormat; + } +} + QSurfaceFormat surfaceFormat() { - return Q3DSEngine::surfaceFormat(); + return surfaceFormatAdopted ? adoptedSurfaceFormat : idealSurfaceFormat(); } Q3DSGraphicsLimits graphicsLimits() { - Q3DSEngine::surfaceFormat(); + if (!surfaceFormatAdopted) { + // make sure gfxLimits is filled in + idealSurfaceFormat(); + } return gfxLimits; } } @@ -790,19 +814,41 @@ bool Q3DSEngine::buildSubUipPresentationScene(UipPresentation *pres) pres->subPres.colorTex->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); pres->subPres.colorTex->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); color->setTexture(pres->subPres.colorTex); - - Qt3DRender::QRenderTargetOutput *ds = new Qt3DRender::QRenderTargetOutput; - ds->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::DepthStencil); - pres->subPres.dsTex = new Qt3DRender::QTexture2D(entityParent); - pres->subPres.dsTex->setFormat(Qt3DRender::QAbstractTexture::D24S8); - pres->subPres.dsTex->setWidth(pres3DS->presentationWidth()); - pres->subPres.dsTex->setHeight(pres3DS->presentationHeight()); - pres->subPres.dsTex->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); - pres->subPres.dsTex->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); - ds->setTexture(pres->subPres.dsTex); - rt->addOutput(color); - rt->addOutput(ds); + + if (gfxLimits.packedDepthStencilBufferSupported) { + Qt3DRender::QRenderTargetOutput *ds = new Qt3DRender::QRenderTargetOutput; + ds->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::DepthStencil); + pres->subPres.depthOrDepthStencilTex = new Qt3DRender::QTexture2D(entityParent); + pres->subPres.depthOrDepthStencilTex->setFormat(Qt3DRender::QAbstractTexture::D24S8); + pres->subPres.depthOrDepthStencilTex->setWidth(pres3DS->presentationWidth()); + pres->subPres.depthOrDepthStencilTex->setHeight(pres3DS->presentationHeight()); + pres->subPres.depthOrDepthStencilTex->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); + pres->subPres.depthOrDepthStencilTex->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); + ds->setTexture(pres->subPres.depthOrDepthStencilTex); + rt->addOutput(ds); + } else { + Qt3DRender::QRenderTargetOutput *depth = new Qt3DRender::QRenderTargetOutput; + depth->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Depth); + pres->subPres.depthOrDepthStencilTex = new Qt3DRender::QTexture2D(entityParent); + pres->subPres.depthOrDepthStencilTex->setFormat(Qt3DRender::QAbstractTexture::D16); + pres->subPres.depthOrDepthStencilTex->setWidth(pres3DS->presentationWidth()); + pres->subPres.depthOrDepthStencilTex->setHeight(pres3DS->presentationHeight()); + pres->subPres.depthOrDepthStencilTex->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); + pres->subPres.depthOrDepthStencilTex->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); + depth->setTexture(pres->subPres.depthOrDepthStencilTex); + rt->addOutput(depth); + Qt3DRender::QRenderTargetOutput *stencil = new Qt3DRender::QRenderTargetOutput; + stencil->setAttachmentPoint(Qt3DRender::QRenderTargetOutput::Stencil); + pres->subPres.stencilTex = new Qt3DRender::QTexture2D(entityParent); + pres->subPres.stencilTex->setFormat(Qt3DRender::QAbstractTexture::TextureFormat(0x1901)); // GL_STENCIL_INDEX + pres->subPres.stencilTex->setWidth(pres3DS->presentationWidth()); + pres->subPres.stencilTex->setHeight(pres3DS->presentationHeight()); + pres->subPres.stencilTex->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); + pres->subPres.stencilTex->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); + stencil->setTexture(pres->subPres.stencilTex); + rt->addOutput(stencil); + } rtSel->setTarget(rt); params.frameGraphRoot = rtSel; diff --git a/src/runtime/q3dsengine_p.h b/src/runtime/q3dsengine_p.h index 946f7a1..841e5e1 100644 --- a/src/runtime/q3dsengine_p.h +++ b/src/runtime/q3dsengine_p.h @@ -96,7 +96,6 @@ public: }; Q_DECLARE_FLAGS(Flags, Flag) - static QSurfaceFormat surfaceFormat(); static void clearLog(); Flags flags() const { return m_flags; } diff --git a/src/runtime/q3dsgraphexplorer.cpp b/src/runtime/q3dsgraphexplorer.cpp index 89d7063..be5973d 100644 --- a/src/runtime/q3dsgraphexplorer.cpp +++ b/src/runtime/q3dsgraphexplorer.cpp @@ -234,7 +234,7 @@ Q3DSGraphExplorer::Q3DSGraphExplorer(Q3DSGraphObject *root, QWidget *parent) s += tr("\n%1 %2").arg((quintptr) slideObj, 0, 16).arg(QString::fromUtf8(slideObj->id())); if (slide->parent()) { s += tr("\n\nProperty changes:"); - const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> &a = slide->propertyChanges(); + const auto &a = slide->propertyChanges(); for (auto it = a.cbegin(), ite = a.cend(); it != ite; ++it) { s += tr("\nOn object %1 %2").arg((quintptr) it.key(), 0, 16).arg(QString::fromUtf8(it.key()->id())); for (auto pit = it.value()->cbegin(), pite = it.value()->cend(); pit != pite; ++pit) diff --git a/src/runtime/q3dsruntimeglobal_p.h b/src/runtime/q3dsruntimeglobal_p.h index 9ed5bf0..4f19bd1 100644 --- a/src/runtime/q3dsruntimeglobal_p.h +++ b/src/runtime/q3dsruntimeglobal_p.h @@ -48,6 +48,10 @@ QT_BEGIN_NAMESPACE +namespace Q3DS { +Q3DSV_PRIVATE_EXPORT void adoptSurfaceFormat(const QSurfaceFormat &format); +} + QT_END_NAMESPACE #endif // Q3DSRUNTIMEGLOBAL_P_H diff --git a/src/runtime/q3dsscenemanager.cpp b/src/runtime/q3dsscenemanager.cpp index 85356e7..877a733 100644 --- a/src/runtime/q3dsscenemanager.cpp +++ b/src/runtime/q3dsscenemanager.cpp @@ -514,7 +514,6 @@ void Q3DSSceneManager::setCurrentSlide(Q3DSSlide *newSlide, bool fromSlidePlayer m_currentSlide = newSlide; } -// TODO: Only called from the slide test, but we keep it working for now... void Q3DSSceneManager::setComponentCurrentSlide(Q3DSComponentNode *component, Q3DSSlide *newSlide) { Q3DSSlideAttached *data = component->masterSlide()->attached<Q3DSSlideAttached>(); @@ -537,11 +536,7 @@ void Q3DSSceneManager::setLayerCaching(bool enabled) void Q3DSSceneManager::prepareAnimators() { - auto slideDeck = m_slidePlayer->slideDeck(); - if ((m_slidePlayer->mode() == Q3DSSlidePlayer::PlayerMode::Viewer) - && (slideDeck->currentSlide()->initialPlayState() == Q3DSSlide::Play)) { - m_slidePlayer->play(); - } + m_slidePlayer->sceneReady(); } QDebug operator<<(QDebug dbg, const Q3DSSceneManager::SceneBuilderParams &p) @@ -575,7 +570,7 @@ void Q3DSSceneManager::prepareEngineResetGlobal() Q3DSShaderManager::instance().invalidate(); } -/*! +/* Builds and "runs" a Qt 3D scene. To be called once per SceneManager instance. Ownership of the generated Qt 3D objects is managed primarily via parenting @@ -796,7 +791,7 @@ Q3DSSceneManager::Scene Q3DSSceneManager::buildScene(Q3DSUipPresentation *presen return sc; } -/*! +/* To be called on the scenemanager corresponding to the main presentation once after all subpresentation buildScene() calls have succeeded. This is where the association of textures and subpresentation layers happens. That @@ -1214,9 +1209,13 @@ void Q3DSSceneManager::buildSubPresentationLayer(Q3DSLayerNode *layer3DS, const // Resize the offscreen subpresentation buffers it->colorTex->setWidth(layerPixelSize.width()); it->colorTex->setHeight(layerPixelSize.height()); - if (it->dsTex) { - it->dsTex->setWidth(layerPixelSize.width()); - it->dsTex->setHeight(layerPixelSize.height()); + if (it->depthOrDepthStencilTex) { + it->depthOrDepthStencilTex->setWidth(layerPixelSize.width()); + it->depthOrDepthStencilTex->setHeight(layerPixelSize.height()); + } + if (it->stencilTex) { + it->stencilTex->setWidth(layerPixelSize.width()); + it->stencilTex->setHeight(layerPixelSize.height()); } // and communicate the new size to the subpresentation's renderer // (viewport, camera, etc. need to adapt), just like a window would @@ -6584,77 +6583,6 @@ bool Q3DSSceneManager::isComponentVisible(Q3DSComponentNode *component) return visible; } -void Q3DSSceneManager::handleSlideChange(Q3DSSlide *prevSlide, - Q3DSSlide *currentSlide) -{ - Q_ASSERT(currentSlide->attached()); - - if (prevSlide) { - auto slideData = static_cast<Q3DSSlideAttached *>(prevSlide->attached()); - for (Q3DSNode *node : qAsConst(slideData->needsMasterRollback)) { - const Q3DSPropertyChangeList *changeList = node->masterRollbackList(); - if (changeList) { - qCDebug(lcScene, "Rolling back %d changes to master for %s", changeList->count(), node->id().constData()); - node->applyPropertyChanges(*changeList); - node->notifyPropertyChanges(*changeList); - updateSubTreeRecursive(node); - } - } - slideData->needsMasterRollback.clear(); - } - - // Find properties on targets that has dynamic properties. - // TODO: Find a better solution (e.g., there can be duplicate updates for e.g., xyz here). - QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> dynamicPropertyChanges; - QVector<Q3DSPropertyChangeList *> ephemeralObjects; - const auto &tracks = currentSlide->animations(); - std::find_if(tracks.cbegin(), tracks.cend(), [&dynamicPropertyChanges, &ephemeralObjects](const Q3DSAnimationTrack &track) { - if (track.isDynamic()) { - auto foundIt = dynamicPropertyChanges.find(track.target()); - const bool propertyFound = (foundIt != dynamicPropertyChanges.end()); - Q3DSPropertyChangeList *changesList = propertyFound - ? *foundIt - : new Q3DSPropertyChangeList; - if (!propertyFound) - ephemeralObjects.push_back(changesList); - - const QString property = track.property().split('.')[0]; - const auto value = track.target()->propertyValue(property); - changesList->append(Q3DSPropertyChange::fromVariant(property, value)); - - if (foundIt == dynamicPropertyChanges.end()) - dynamicPropertyChanges.insert(track.target(), changesList); - } - return false; - }); - - const auto &propertyChanges = currentSlide->propertyChanges(); - - // Filter out properties that we needs to be marked dirty, i.e., eyeball changes. - QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> notifyPropertyChanges; - for (auto it = propertyChanges.cbegin(); it != propertyChanges.cend(); ++it) { - std::find_if((*it)->cbegin(), (*it)->cend(), [it, ¬ifyPropertyChanges, &ephemeralObjects](const Q3DSPropertyChange &propChange) { - if (propChange.name() == QLatin1String("eyeball")) { - Q3DSPropertyChangeList *propChangeList = new Q3DSPropertyChangeList; - propChangeList->append(propChange); - ephemeralObjects.push_back(propChangeList); - notifyPropertyChanges[it.key()] = propChangeList; - return true; - } - return false; - }); - } - // We avoid triggering notifications (i.e., setting dirty flags) just yet, as we - // want to defer that until we're ready. - m_presentation->applyPropertyChanges(propertyChanges); - // notify about visibility changes. - m_presentation->notifyPropertyChanges(notifyPropertyChanges); - // Now re-apply the original values for those dynamic keyframes. - m_presentation->applyPropertyChanges(dynamicPropertyChanges); - // Now clean-up the objects we created. - qDeleteAll(ephemeralObjects); -} - void Q3DSSceneManager::prepareNextFrame() { m_wasDirty = false; @@ -6883,6 +6811,7 @@ void Q3DSSceneManager::updateSubTreeRecursive(Q3DSGraphObject *obj) Q3DSModelAttached *modelData = static_cast<Q3DSModelAttached *>(data->model3DS->attached()); data->opacity = modelData->globalOpacity * (mat3DS->opacity() / 100.0f); updateDefaultMaterial(mat3DS); + retagSubMeshes(data->model3DS); m_wasDirty = true; markLayerForObjectDirty(mat3DS); if (data->frameChangeFlags & Q3DSDefaultMaterial::BlendModeChanges) @@ -6898,6 +6827,7 @@ void Q3DSSceneManager::updateSubTreeRecursive(Q3DSGraphObject *obj) Q3DSModelAttached *modelData = static_cast<Q3DSModelAttached *>(data->model3DS->attached()); data->opacity = modelData->globalOpacity; updateCustomMaterial(mat3DS); + retagSubMeshes(data->model3DS); m_wasDirty = true; markLayerForObjectDirty(mat3DS); } @@ -7192,10 +7122,14 @@ void Q3DSSceneManager::changeSlideByName(Q3DSGraphObject *sceneOrComponent, cons }); if (targetSlide) { - if (component) - component->setCurrentSlide(targetSlide); - else + if (component) { + if (m_currentSlide->objects().contains(component) || m_masterSlide->objects().contains(component)) + setComponentCurrentSlide(component, targetSlide); + else + component->setCurrentSlide(targetSlide); + } else { setCurrentSlide(targetSlide); + } } else { qWarning("changeSlideByName: Slide %s not found on %s", qPrintable(name), sceneOrComponent->id().constData()); } @@ -7296,10 +7230,19 @@ void Q3DSSceneManager::setDataInputValue(const QString &dataInputName, const QVa // timeline length and map the incoming value on it (just because 3DS1 // does it). If min-max is not specified, interpret value directly as // timeline point in milliseconds - const float seekTimeMs = meta.hasMinMax() - ? ((value.toFloat() - meta.minValue) / - (meta.maxValue - meta.minValue))* obj->endTime() - : value.toFloat(); + float seekTimeMs = 0.0f; + if (meta.hasMinMax()) { + Q_ASSERT(!qFuzzyIsNull(meta.maxValue)); + const float normalized = qBound(0.0f, (value.toFloat() / (meta.maxValue - meta.minValue)), 1.0f); + Q3DSSlide *slide = (obj->type() == Q3DSGraphObject::Component) ? static_cast<Q3DSComponentNode *>(obj)->currentSlide() + : m_currentSlide; + qint32 startTime = 0; + qint32 endTime = 0; + Q3DSSlideUtils::getStartAndEndTime(slide, &startTime, &endTime); + seekTimeMs = normalized * (endTime - startTime); + } else { + seekTimeMs = value.toFloat(); + } goToTime(obj, seekTimeMs); } else { qWarning("Object %s with timeline data input is not Scene or Component", obj->id().constData()); diff --git a/src/runtime/q3dsscenemanager_p.h b/src/runtime/q3dsscenemanager_p.h index fc494aa..d569284 100644 --- a/src/runtime/q3dsscenemanager_p.h +++ b/src/runtime/q3dsscenemanager_p.h @@ -592,7 +592,8 @@ struct Q3DSSubPresentation QString id; Q3DSSceneManager *sceneManager = nullptr; Qt3DRender::QAbstractTexture *colorTex = nullptr; - Qt3DRender::QAbstractTexture *dsTex = nullptr; + Qt3DRender::QAbstractTexture *depthOrDepthStencilTex = nullptr; + Qt3DRender::QAbstractTexture *stencilTex = nullptr; }; struct Q3DSGuiData @@ -819,8 +820,6 @@ private: void prepareNextFrame(); bool isComponentVisible(Q3DSComponentNode *component); - void handleSlideChange(Q3DSSlide *previousSlide, - Q3DSSlide *currentSlide); void setNodeVisibility(Q3DSNode *node, bool visible); void handleSceneChange(Q3DSScene *scene, Q3DSGraphObject::DirtyFlag change, Q3DSGraphObject *obj); diff --git a/src/runtime/q3dsslideplayer.cpp b/src/runtime/q3dsslideplayer.cpp index fee148c..f7c2ee2 100644 --- a/src/runtime/q3dsslideplayer.cpp +++ b/src/runtime/q3dsslideplayer.cpp @@ -44,45 +44,63 @@ QT_BEGIN_NAMESPACE -// NOTE: We assume that the properties for the layer has been applied before this is called -// if it hasn't it will either return the previous value or the odl value void Q3DSSlideUtils::getStartAndEndTime(Q3DSSlide *slide, qint32 *startTime, qint32 *endTime) { Q_ASSERT(startTime != nullptr || endTime != nullptr); - qint32 eTime = -1; + qint32 layerEndTime = -1; + qint32 nodesEndtime = -1; - // First go through the slide's parent (master slide) and look for layers which have - // endtime explicitly set by this slide's property changes + // Check if there are nodes from the parent slide that has property changes on this slide. if (Q3DSSlide *p = static_cast<Q3DSSlide *>(slide->parent())) { for (auto *obj : p->objects()) { - if (obj->type() != Q3DSGraphObject::Layer) + if (!obj->isNode()) continue; - const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> props = - slide->propertyChanges(); - const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *>::const_iterator it = - props.find(obj); - if (it == props.constEnd()) + // Look for property updates on "this" slide. + const auto &props = slide->propertyChanges(); + const auto foundIt = props.constFind(obj); + if (foundIt == props.constEnd()) continue; - if ((*it)->keys().contains(QStringLiteral("endtime")) && obj->endTime() > eTime) - eTime = obj->endTime(); + + // If there are property changes for the object, check if it has a new endtime. + std::find_if(foundIt.value()->cbegin(), foundIt.value()->cend(), [&layerEndTime, &nodesEndtime, obj](const Q3DSPropertyChange &propChange) { + if (propChange.name() == QLatin1String("endtime")) { + bool ok = false; + const qint32 value = propChange.value().toInt(&ok); + if (ok) { + if (obj->type() == Q3DSGraphObject::Layer && (value > layerEndTime)) + layerEndTime = value; + else if (value > nodesEndtime) + nodesEndtime = value; + } + } + return false; + }); } } - // Now look for the endtime from the slides explicit layer objects + // Now look for the endtime on nodes on this slide. for (const auto obj : slide->objects()) { - if (obj->type() != Q3DSGraphObject::Layer) + // Skip non-node types. + if (!obj->isNode()) continue; - if (obj->endTime() > eTime) - eTime = obj->endTime(); + // We collect both layer endtimes (if any) and object endtimes in one go. + if (obj->type() == Q3DSGraphObject::Layer && (obj->endTime() > layerEndTime)) + layerEndTime = obj->endTime(); + else if (obj->endTime() > nodesEndtime) + nodesEndtime = obj->endTime(); } + // Final fallback, if neither was found use the value set by the slide. + if (layerEndTime == -1 && nodesEndtime == -1) + nodesEndtime = slide->endTime(); + if (startTime) *startTime = slide->startTime(); if (endTime) - *endTime = eTime != -1 ? eTime : slide->endTime(); + *endTime = layerEndTime != -1 ? layerEndTime : nodesEndtime; } static QString getSlideName(Q3DSSlide *slide) @@ -97,40 +115,28 @@ static Q3DSSlidePlayer::PlayerState getInitialSlideState(Q3DSSlide *slide) } -static void updatePosition(Q3DSSlide *slide, float pos, float duration) +static void updatePosition(Q3DSSlide *slide, float newTimeMs, float durationMs) { - const auto updateAnimator = [pos](Qt3DAnimation::QClipAnimator *animator, float duration) { + const auto updateAnimator = [newTimeMs](Qt3DAnimation::QClipAnimator *animator, float durationMs) { if (!animator) return; - const float nt = qBound(0.0f, pos / duration, 1.0f); + const float nt = qBound(0.0f, newTimeMs / durationMs, 1.0f); // NOTE!!!: This is a bit funky, but it means we can avoid tracking the normalized values in the // frontend node. This of course assumes that the limit in the fuzzy compare doesn't change! animator->setNormalizedTime(qFuzzyCompare(nt, animator->normalizedTime()) ? qAbs(nt - (1.0f / 100000.0f)) : nt); }; const auto updateAnimators = [&updateAnimator](const QVector<Qt3DAnimation::QClipAnimator *> &animators) { for (auto animator : animators) { - const float duration = animator->clip()->duration() * 1000.0f; - updateAnimator(animator, duration); - } - }; - - const auto updateAllComponentPlayers = [pos](Q3DSSlide *slide) { - for (auto obj : slide->objects()) { - if (obj->type() == Q3DSGraphObject::Component) { - Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj); - const float slidePos = pos - obj->startTime(); - Q3DSSlidePlayer *player = comp->masterSlide()->attached<Q3DSSlideAttached>()->slidePlayer; - player->seek(slidePos); - } + const float durationMs = animator->clip()->duration() * 1000.0f; + updateAnimator(animator, durationMs); } }; Q3DSSlideAttached *data = slide->attached<Q3DSSlideAttached>(); Q_ASSERT(data); - updateAllComponentPlayers(slide); - updateAnimator(data->animator, duration); + updateAnimator(data->animator, durationMs); updateAnimators(data->animators); }; @@ -144,12 +150,11 @@ static void updateAnimators(Q3DSSlide *slide, bool running, bool restart, float // NOTE!!!: This is a bit funky, but it means we can avoid tracking the normalized values in the // frontend node. This of course assumes that the limit in the fuzzy compare doesn't change! animator->setNormalizedTime(qFuzzyCompare(animator->normalizedTime(), 0.0f) ? (0.0f + (1.0f / 100000.0f)) : 0.0f); - // NOTE: The running value might not have been updated in the frontend node yet, - // so force update this one as well! - if (animator->isRunning()) - animator->setRunning(false); } animator->clock()->setPlaybackRate(double(rate)); + // NOTE: The running value might not have been updated in the frontend node yet, + // so force update if the values are the same... + animator->setRunning(!running); animator->setRunning(running); }; const auto updateAnimators = [&updateAnimator](const QVector<Qt3DAnimation::QClipAnimator *> &animators) { @@ -157,24 +162,9 @@ static void updateAnimators(Q3DSSlide *slide, bool running, bool restart, float updateAnimator(animator); }; - const auto updateAllComponentPlayers = [running](Q3DSSlide *slide) { - for (auto obj : slide->objects()) { - if (obj->type() == Q3DSGraphObject::Component) { - Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj); - Q3DSSlide *compSlide = comp->currentSlide(); - Q3DSSlidePlayer *player = comp->masterSlide()->attached<Q3DSSlideAttached>()->slidePlayer; - if (running && compSlide->initialPlayState() == Q3DSSlide::Play) - player->play(); - else - player->stop(); - } - } - }; - Q3DSSlideAttached *data = slide->attached<Q3DSSlideAttached>(); Q_ASSERT(data); - updateAllComponentPlayers(slide); updateAnimator(data->animator); updateAnimators(data->animators); } @@ -192,20 +182,9 @@ static void updatePlaybackRate(Q3DSSlide *slide, float rate) updateAnimator(animator); }; - const auto updateAllComponentPlayers = [rate](Q3DSSlide *slide) { - for (auto obj : slide->objects()) { - if (obj->type() == Q3DSGraphObject::Component) { - Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj); - Q3DSSlidePlayer *player = comp->masterSlide()->attached<Q3DSSlideAttached>()->slidePlayer; - player->setPlaybackRate(rate); - } - } - }; - Q3DSSlideAttached *data = slide->attached<Q3DSSlideAttached>(); Q_ASSERT(data); - updateAllComponentPlayers(slide); updateAnimator(data->animator); updateAnimators(data->animators); } @@ -214,7 +193,7 @@ Q3DSSlidePlayer::Q3DSSlidePlayer(Q3DSSceneManager *sceneManager, QObject *parent) : QObject(parent) , m_sceneManager(sceneManager) - , m_animationManager(new Q3DSAnimationManager(this)) + , m_animationManager(new Q3DSAnimationManager) { } @@ -236,6 +215,43 @@ void Q3DSSlidePlayer::advanceFrame() m_animationManager->applyChanges(); } +void Q3DSSlidePlayer::sceneReady() +{ + Q3DSSlideDeck *slideDeck = m_data.slideDeck; + if (!slideDeck) + return; + + Q3DSSlide *currentSlide = slideDeck->currentSlide(); + Q_ASSERT(currentSlide); + + const bool viewerMode = (m_mode == PlayerMode::Viewer); + if (viewerMode && (currentSlide->initialPlayState() == Q3DSSlide::Play)) + play(); + else + pause(); + + // In viewer-mode we need to go through all components players as well + if (viewerMode) { + static const auto notifyComponentPlayers = [](Q3DSSlide *slide) { + if (!slide) + return; + + const auto &objects = slide->objects(); + std::find_if(objects.constBegin(), objects.constEnd(), [](Q3DSGraphObject *obj) { + if (obj->type() == Q3DSGraphObject::Component) { + Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj); + Q3DSSlide *compSlide = comp->currentSlide(); + Q3DSSlidePlayer *player = compSlide->attached<Q3DSSlideAttached>()->slidePlayer; + player->sceneReady(); + } + return false; + }); + }; + notifyComponentPlayers(static_cast<Q3DSSlide *>(currentSlide->parent())); + notifyComponentPlayers(currentSlide); + } +} + float Q3DSSlidePlayer::duration() const { if (m_data.state == PlayerState::Idle) @@ -304,9 +320,14 @@ void Q3DSSlidePlayer::stop() void Q3DSSlidePlayer::pause() { - if (m_data.state != PlayerState::Playing) + if (m_data.state == PlayerState::Paused) return; + if (m_data.state == PlayerState::Idle) { + qCWarning(lcSlidePlayer) << "Pause called in Idle state (no content)"; + return; + } + setInternalState(PlayerState::Paused); } @@ -378,8 +399,6 @@ void Q3DSSlidePlayer::setSlideDeck(Q3DSSlideDeck *slideDeck) // Create a slide deck for this component compMasterData->slidePlayer->setSlideDeck(new Q3DSSlideDeck(compMasterSlide, slide)); } - - Q_ASSERT(compMasterData->slidePlayer->state() == PlayerState::Ready); }; const auto forAllComponentsOnSlide = [this, prepareComponentsOnSlide](Q3DSSlide *slide) { @@ -546,10 +565,28 @@ void Q3DSSlidePlayer::handleCurrentSlideChanged(Q3DSSlide *slide, qCDebug(lcSlidePlayer, "Handling current slide change: from slide \"%s\", to slide \"%s\"", qPrintable(getSlideName(previousSlide)), qPrintable(getSlideName(slide))); + static const auto cleanUpComponentPlayers = [](Q3DSSlide *slide) { + if (!slide) + return; + + const auto &objects = slide->objects(); + std::find_if(objects.constBegin(), objects.constEnd(), [](Q3DSGraphObject *obj) { + if (obj->type() == Q3DSGraphObject::Component) { + Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj); + Q3DSSlide *compSlide = comp->currentSlide(); + Q3DSSlideAttached *data = compSlide->attached<Q3DSSlideAttached>(); + data->slidePlayer->handleCurrentSlideChanged(nullptr, compSlide); + } + return false; + }); + }; if (previousSlide && slideDidChange) { - if (parentChanged) + if (parentChanged) { + cleanUpComponentPlayers(static_cast<Q3DSSlide *>(previousSlide->parent())); setSlideTime(static_cast<Q3DSSlide *>(previousSlide->parent()), -1.0f); + } setSlideTime(previousSlide, -1.0f); + cleanUpComponentPlayers(previousSlide); Q3DSSlideAttached *data = previousSlide->attached<Q3DSSlideAttached>(); if (data && data->animator) { // TODO: We probably want to be a bit less brute. @@ -560,9 +597,8 @@ void Q3DSSlidePlayer::handleCurrentSlideChanged(Q3DSSlide *slide, } if (slide && slideDidChange && isSlideVisible(slide)) { - m_sceneManager->handleSlideChange(previousSlide, slide); + processPropertyChanges(slide, previousSlide); m_animationManager->updateAnimations(slide, (m_mode == PlayerMode::Editor)); - if (parentChanged) setSlideTime(static_cast<Q3DSSlide *>(slide->parent()), 0.0f); setSlideTime(slide, 0.0f); @@ -603,6 +639,26 @@ void Q3DSSlidePlayer::handleCurrentSlideChanged(Q3DSSlide *slide, qint32 endTime = 0; Q3DSSlideUtils::getStartAndEndTime(slide, &startTime, &endTime); onDurationChanged(endTime - startTime); + + static const auto updateComponentSlides = [](Q3DSSlide *slide) { + if (!slide) + return; + const auto &objects = slide->objects(); + std::find_if(objects.constBegin(), objects.constEnd(), [](Q3DSGraphObject *obj) { + if (obj->type() == Q3DSGraphObject::Component) { + Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj); + Q3DSSlide *compSlide = comp->currentSlide(); + Q3DSSlideAttached *data = compSlide->attached<Q3DSSlideAttached>(); + data->slidePlayer->handleCurrentSlideChanged(compSlide, nullptr); + if (data->slidePlayer->m_mode == PlayerMode::Viewer) + data->slidePlayer->setInternalState(getInitialSlideState(compSlide)); + } + return false; + }); + }; + if (parentChanged) + updateComponentSlides(static_cast<Q3DSSlide *>(slide->parent())); + updateComponentSlides(slide); } if (previousSlide != slide) @@ -646,27 +702,6 @@ void Q3DSSlidePlayer::setSlideTime(Q3DSSlide *slide, float time, bool parentVisi && node->flags().testFlag(Q3DSNode::Active) && static_cast<Q3DSNodeAttached *>(node->attached())->globalVisibility; - if (obj->type() == Q3DSGraphObject::Component) { - Q3DSComponentNode *comp = static_cast<Q3DSComponentNode *>(obj); - Q3DSSlide *compMasterSlide = comp->masterSlide(); - Q_ASSERT(compMasterSlide); - Q3DSSlidePlayer *compPlayer = compMasterSlide->attached<Q3DSSlideAttached>()->slidePlayer; - Q_ASSERT(compPlayer); - - const float slideTime = time - obj->startTime(); - compPlayer->setSlideTime(compMasterSlide, slideTime, shouldBeVisible); - - if (!shouldBeVisible) { - Q3DSGraphObject *n = compMasterSlide->firstChild(); - while (n) { - compPlayer->setSlideTime(static_cast<Q3DSSlide *>(n), slideTime, shouldBeVisible); - n = n->nextSibling(); - } - } else { - compPlayer->setSlideTime(comp->currentSlide(), slideTime); - } - } - if (forceUpdate || shouldBeVisible != nodeHasVisibilityTag(node)) updateNodeVisibility(node, shouldBeVisible); } @@ -686,7 +721,7 @@ void Q3DSSlidePlayer::sendPositionChanged(Q3DSSlide *slide, float pos) if (!qFuzzyCompare(oldPosition, pos)) Q_EMIT positionChanged(pos); - const bool onEOS = (m_data.state == PlayerState::Playing) + const bool onEOS = (m_data.state == PlayerState::Playing && m_data.pendingState == PlayerState::Playing) && ((m_data.position == 0.0f && m_data.playbackRate < 0.0f) || (m_data.position == duration() && m_data.playbackRate > 0.0f)); @@ -713,7 +748,9 @@ bool Q3DSSlidePlayer::isSlideVisible(Q3DSSlide *slide) if (slide) { Q3DSSlidePlayer *player = slide->attached<Q3DSSlideAttached>()->slidePlayer; Q3DSSlideDeck *slideDeck = player->slideDeck(); - if (slideDeck->currentSlide() == slide) { + const bool isMasterSlide = (slideDeck->masterSlide() == slide); + const bool isCurrentSlide = (slideDeck->currentSlide() == slide); + if (isCurrentSlide || isMasterSlide) { Q3DSSlide *parentSlide = slideDeck->parentSlide(); if (parentSlide) { // We're a component and current, continue up the ladder... @@ -731,6 +768,60 @@ bool Q3DSSlidePlayer::isSlideVisible(Q3DSSlide *slide) return visible; } +void Q3DSSlidePlayer::processPropertyChanges(Q3DSSlide *currentSlide, + Q3DSSlide *previousSlide) +{ + Q_ASSERT(currentSlide->attached()); + + if (previousSlide) { + auto slideData = static_cast<Q3DSSlideAttached *>(previousSlide->attached()); + for (Q3DSNode *node : qAsConst(slideData->needsMasterRollback)) { + const Q3DSPropertyChangeList *changeList = node->masterRollbackList(); + if (changeList) { + qCDebug(lcScene, "Rolling back %d changes to master for %s", changeList->count(), node->id().constData()); + node->applyPropertyChanges(*changeList); + node->notifyPropertyChanges(*changeList); + m_sceneManager->updateSubTreeRecursive(node); + } + } + slideData->needsMasterRollback.clear(); + } + + // Find properties on targets that has dynamic properties. + // TODO: Find a better solution (e.g., there can be duplicate updates for e.g., xyz here). + QHash<Q3DSGraphObject *, Q3DSPropertyChangeList> dynamicPropertyChanges; + const auto &tracks = currentSlide->animations(); + std::find_if(tracks.cbegin(), tracks.cend(), [&dynamicPropertyChanges](const Q3DSAnimationTrack &track) { + if (track.isDynamic()) { + auto foundIt = dynamicPropertyChanges.constFind(track.target()); + Q3DSPropertyChangeList changeList; + if (foundIt != dynamicPropertyChanges.constEnd()) + changeList = *foundIt; + const QString property = track.property().split('.')[0]; + const auto value = track.target()->propertyValue(property); + changeList.append(Q3DSPropertyChange::fromVariant(property, value)); + dynamicPropertyChanges[track.target()] = changeList; + } + return false; + }); + + // Filter out properties that we needs to be marked dirty, i.e., eyeball changes. + const auto &propertyChanges = currentSlide->propertyChanges(); + for (auto it = propertyChanges.cbegin(); it != propertyChanges.cend(); ++it) { + std::find_if((*it)->cbegin(), (*it)->cend(), [it](const Q3DSPropertyChange &propChange) { + if (propChange.name() == QLatin1String("eyeball")) + it.key()->notifyPropertyChanges(*it.value()); + + it.key()->applyPropertyChanges(*it.value()); + return false; + }); + } + + // Now update the propeties from dynamic property values + for (auto it = dynamicPropertyChanges.cbegin(), ite = dynamicPropertyChanges.cend(); it != ite; ++it) + it.key()->applyPropertyChanges(it.value()); +} + void Q3DSSlidePlayer::onDurationChanged(float duration) { if (qFuzzyCompare(duration, m_data.duration)) diff --git a/src/runtime/q3dsslideplayer_p.h b/src/runtime/q3dsslideplayer_p.h index 11dd8c2..01020e2 100644 --- a/src/runtime/q3dsslideplayer_p.h +++ b/src/runtime/q3dsslideplayer_p.h @@ -95,6 +95,7 @@ public: Q3DSSlideDeck *slideDeck() const; void advanceFrame(); + void sceneReady(); float duration() const; float position() const; @@ -145,6 +146,8 @@ private: void sendPositionChanged(Q3DSSlide *slide, float pos); void updateNodeVisibility(Q3DSNode *node, bool visible); bool isSlideVisible(Q3DSSlide *slide); + void processPropertyChanges(Q3DSSlide *currentSlide, + Q3DSSlide *previousSlide); struct Data { Q3DSSlideDeck *slideDeck = nullptr; diff --git a/src/runtime/q3dsuippresentation.cpp b/src/runtime/q3dsuippresentation.cpp index 5119b49..3633a2a 100644 --- a/src/runtime/q3dsuippresentation.cpp +++ b/src/runtime/q3dsuippresentation.cpp @@ -3878,8 +3878,8 @@ QHash<QString, bool> &Q3DSUipPresentation::imageTransparencyHash() return m_imageTransparencyHash; } -/*! - Maps a raw XML filename ref like ".\Headphones\meshes\Headphones.mesh#1" +/* + Maps a raw XML filename ref like "./Headphones/meshes/Headphones.mesh#1" onto a fully qualified filename that can be opened as-is (even if the uip is in qrc etc.), and also decodes the optional part index. */ @@ -4093,13 +4093,13 @@ void Q3DSUipPresentation::removeDataInputTarget(Q3DSGraphObject *obj) } } -void Q3DSUipPresentation::notifyPropertyChanges(const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> &changeList) const +void Q3DSUipPresentation::notifyPropertyChanges(const Q3DSSlide::PropertyChanges &changeList) const { for (auto it = changeList.cbegin(), ite = changeList.cend(); it != ite; ++it) it.key()->notifyPropertyChanges(*it.value()); } -void Q3DSUipPresentation::applyPropertyChanges(const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> &changeList) const +void Q3DSUipPresentation::applyPropertyChanges(const Q3DSSlide::PropertyChanges &changeList) const { for (auto it = changeList.cbegin(), ite = changeList.cend(); it != ite; ++it) { for (auto change = it.value()->begin(); change != it.value()->end(); change++) diff --git a/src/runtime/q3dsuippresentation_p.h b/src/runtime/q3dsuippresentation_p.h index 1f73a98..bc4bec3 100644 --- a/src/runtime/q3dsuippresentation_p.h +++ b/src/runtime/q3dsuippresentation_p.h @@ -596,6 +596,8 @@ public: Value }; + using PropertyChanges = QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *>; + Q3DSSlide(); ~Q3DSSlide(); @@ -607,7 +609,7 @@ public: void addObject(Q3DSGraphObject *obj); void removeObject(Q3DSGraphObject *obj); - const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> &propertyChanges() const { return m_propChanges; } + const PropertyChanges &propertyChanges() const { return m_propChanges; } void addPropertyChanges(Q3DSGraphObject *target, Q3DSPropertyChangeList *changeList); // changeList ownership transferred void removePropertyChanges(Q3DSGraphObject *target); Q3DSPropertyChangeList *takePropertyChanges(Q3DSGraphObject *target); @@ -679,7 +681,7 @@ private: PlayThrough m_playThrough = Next; QVariant m_playThroughValue; QSet<Q3DSGraphObject *> m_objects; - QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> m_propChanges; + PropertyChanges m_propChanges; QVector<Q3DSAnimationTrack> m_anims; QVector<Q3DSAction> m_actions; QVector<SlideGraphChangeCallback> m_slideGraphChangeCallbacks; // master only @@ -1994,8 +1996,8 @@ public: static void forAllModels(Q3DSGraphObject *obj, std::function<void(Q3DSModelNode *)> f, bool includeHidden = false); void forAllImages(std::function<void(Q3DSImage *)> f); - void notifyPropertyChanges(const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> &changeList) const; - void applyPropertyChanges(const QHash<Q3DSGraphObject *, Q3DSPropertyChangeList *> &changeList) const; + void notifyPropertyChanges(const Q3DSSlide::PropertyChanges &changeList) const; + void applyPropertyChanges(const Q3DSSlide::PropertyChanges &changeList) const; void applySlidePropertyChanges(Q3DSSlide *slide) const; qint64 loadTimeMsecs() const; diff --git a/src/runtime/runtime.pro b/src/runtime/runtime.pro index 483ce2b..8a0c957 100644 --- a/src/runtime/runtime.pro +++ b/src/runtime/runtime.pro @@ -96,4 +96,6 @@ include(shadergenerator/shadergenerator.pri) qtConfig(q3ds-profileui): include(profileui/profileui.pri) +include(doc/doc.pri) + load(qt_module) diff --git a/src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp b/src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp index 5eb616d..6d646da 100644 --- a/src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp +++ b/src/runtime/shadergenerator/q3dscustommaterialvertexpipeline.cpp @@ -213,6 +213,43 @@ struct ShaderGenerator : public Q3DSCustomMaterialShaderGenerator vertexGenerator().beginVertexGeneration(nullptr); } + void addProperties(Q3DSAbstractShaderStageGenerator &fragmentShader) + { + // Add Uniforms from material properties + for (auto property : m_currentMaterial->properties()) { + switch (property.type) { + case Q3DS::Boolean: + fragmentShader.addUniform(property.name.toLocal8Bit(), "bool"); + break; + case Q3DS::Long: + fragmentShader.addUniform(property.name.toLocal8Bit(), "int"); + break; + case Q3DS::FloatRange: + case Q3DS::Float: + case Q3DS::FontSize: + fragmentShader.addUniform(property.name.toLocal8Bit(), "float"); + break; + case Q3DS::Float2: + fragmentShader.addUniform(property.name.toLocal8Bit(), "vec2"); + break; + case Q3DS::Vector: + case Q3DS::Scale: + case Q3DS::Rotation: + case Q3DS::Color: + fragmentShader.addUniform(property.name.toLocal8Bit(), "vec3"); + break; + case Q3DS::Texture: + fragmentShader.addUniform(property.name.toLocal8Bit(), "sampler2D"); + break; + case Q3DS::StringList: + fragmentShader.addUniform(property.name.toLocal8Bit(), "int"); + break; + default: + break; + } + } + } + void generateFragmentShader(const QString &shaderName) { // Get the shader source from the Q3DSCustomMaterial based @@ -290,6 +327,7 @@ struct ShaderGenerator : public Q3DSCustomMaterialShaderGenerator vertexShader.generateWorldPosition(); vertexShader.generateViewVector(); + addProperties(fragmentShader); return; } @@ -331,40 +369,7 @@ struct ShaderGenerator : public Q3DSCustomMaterialShaderGenerator fragmentShader << "}\n\n"; } - // Add Uniforms from material properties - for (auto property : m_currentMaterial->properties()) { - switch (property.type) { - case Q3DS::Boolean: - fragmentShader.addUniform(property.name.toLocal8Bit(), "bool"); - break; - case Q3DS::Long: - fragmentShader.addUniform(property.name.toLocal8Bit(), "int"); - break; - case Q3DS::FloatRange: - case Q3DS::Float: - case Q3DS::FontSize: - fragmentShader.addUniform(property.name.toLocal8Bit(), "float"); - break; - case Q3DS::Float2: - fragmentShader.addUniform(property.name.toLocal8Bit(), "vec2"); - break; - case Q3DS::Vector: - case Q3DS::Scale: - case Q3DS::Rotation: - case Q3DS::Color: - fragmentShader.addUniform(property.name.toLocal8Bit(), "vec3"); - break; - case Q3DS::Texture: - fragmentShader.addUniform(property.name.toLocal8Bit(), "sampler2D"); - break; - case Q3DS::StringList: - fragmentShader.addUniform(property.name.toLocal8Bit(), "int"); - break; - default: - break; - } - } - + addProperties(fragmentShader); // setup main vertexGenerator().beginFragmentGeneration(); diff --git a/src/src.pro b/src/src.pro index d1f86eb..1b02d69 100644 --- a/src/src.pro +++ b/src/src.pro @@ -1,8 +1,7 @@ TEMPLATE = subdirs SUBDIRS += \ - runtime \ - doc + runtime qtHaveModule(quick) { SUBDIRS += imports diff --git a/tests/auto/behaviors/tst_q3dsbehaviors.cpp b/tests/auto/behaviors/tst_q3dsbehaviors.cpp index fdc8da5..9954c77 100644 --- a/tests/auto/behaviors/tst_q3dsbehaviors.cpp +++ b/tests/auto/behaviors/tst_q3dsbehaviors.cpp @@ -69,7 +69,7 @@ void tst_Q3DSBehaviors::initTestCase() if (!isOpenGLGoodEnough()) QSKIP("This platform does not support OpenGL proper"); - QSurfaceFormat::setDefaultFormat(Q3DSEngine::surfaceFormat()); + QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat()); m_engine = new Q3DSEngine; m_view = new Q3DSWindow; m_view->setEngine(m_engine); diff --git a/tests/auto/documents/tst_q3dsdocuments.cpp b/tests/auto/documents/tst_q3dsdocuments.cpp index 61af29e..aee400d 100644 --- a/tests/auto/documents/tst_q3dsdocuments.cpp +++ b/tests/auto/documents/tst_q3dsdocuments.cpp @@ -113,7 +113,7 @@ void tst_Q3DSDocuments::initTestCase() if (!isOpenGLGoodEnough()) QSKIP("This platform does not support OpenGL proper"); - QSurfaceFormat::setDefaultFormat(Q3DSEngine::surfaceFormat()); + QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat()); Q3DSUtils::setDialogsEnabled(false); } diff --git a/tests/auto/q3dslancelot/scenegrabber/main.cpp b/tests/auto/q3dslancelot/scenegrabber/main.cpp index 357b257..6246746 100644 --- a/tests/auto/q3dslancelot/scenegrabber/main.cpp +++ b/tests/auto/q3dslancelot/scenegrabber/main.cpp @@ -150,7 +150,7 @@ int main(int argc, char *argv[]) qSetGlobalQHashSeed(0); QGuiApplication a(argc, argv); - QSurfaceFormat::setDefaultFormat(Q3DSEngine::surfaceFormat()); + QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat()); Q3DSUtils::setDialogsEnabled(false); diff --git a/tests/auto/slideplayer/tst_q3dsslideplayer.cpp b/tests/auto/slideplayer/tst_q3dsslideplayer.cpp index 3593646..96fa78b 100644 --- a/tests/auto/slideplayer/tst_q3dsslideplayer.cpp +++ b/tests/auto/slideplayer/tst_q3dsslideplayer.cpp @@ -101,7 +101,7 @@ void tst_Q3DSSlidePlayer::initTestCase() if (!isOpenGLGoodEnough()) QSKIP("This platform does not support OpenGL proper"); - QSurfaceFormat::setDefaultFormat(Q3DSEngine::surfaceFormat()); + QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat()); m_engine = new Q3DSEngine; m_view = new Q3DSWindow; m_view->setEngine(m_engine); diff --git a/tests/auto/slides/tst_q3dsslides.cpp b/tests/auto/slides/tst_q3dsslides.cpp index cc6a62b..f68835a 100644 --- a/tests/auto/slides/tst_q3dsslides.cpp +++ b/tests/auto/slides/tst_q3dsslides.cpp @@ -133,7 +133,7 @@ void tst_Q3DSSlides::initTestCase() if (!isOpenGLGoodEnough()) QSKIP("This platform does not support OpenGL proper"); - QSurfaceFormat::setDefaultFormat(Q3DSEngine::surfaceFormat()); + QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat()); m_engine = new Q3DSEngine; m_view = new Q3DSWindow; m_view->setEngine(m_engine); diff --git a/tests/manual/qt3dsexplorer/main.cpp b/tests/manual/qt3dsexplorer/main.cpp index e90ecda..0e2b793 100644 --- a/tests/manual/qt3dsexplorer/main.cpp +++ b/tests/manual/qt3dsexplorer/main.cpp @@ -38,7 +38,7 @@ int main(int argc, char *argv[]) { QApplication app(argc, argv); - QSurfaceFormat::setDefaultFormat(Q3DSEngine::surfaceFormat()); + QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat()); QCommandLineParser cmdLineParser; cmdLineParser.addHelpOption(); diff --git a/tools/q3dsviewer/main.cpp b/tools/q3dsviewer/main.cpp index 1c1c15f..306dceb 100644 --- a/tools/q3dsviewer/main.cpp +++ b/tools/q3dsviewer/main.cpp @@ -60,7 +60,7 @@ int main(int argc, char *argv[]) #else QGuiApplication app(argc, argv); #endif - QSurfaceFormat::setDefaultFormat(Q3DSEngine::surfaceFormat()); + QSurfaceFormat::setDefaultFormat(Q3DS::surfaceFormat()); QCommandLineParser cmdLineParser; cmdLineParser.addHelpOption(); @@ -73,12 +73,10 @@ int main(int argc, char *argv[]) cmdLineParser.addOption(msaaOption); QCommandLineOption noProfOption({ "p", "no-profile" }, QObject::tr("Opens presentation without profiling enabled")); cmdLineParser.addOption(noProfOption); - cmdLineParser.addOption({"connect", QObject::tr("main", - "If this parameter is specified, the viewer\n" - "is started in connection mode.\n" - "The default value is 36000."), - QObject::tr("main", "port"), QString::number(36000)}); - + QCommandLineOption remoteOption("port", + QObject::tr("Sets the <port> to listen on in remote connection mode. The default <port> is 36000."), + QObject::tr("port"), QLatin1String("36000")); + cmdLineParser.addOption(remoteOption); cmdLineParser.process(app); #if !defined(Q_OS_ANDROID) && !defined(Q_OS_IOS) @@ -112,8 +110,8 @@ int main(int argc, char *argv[]) // Setup Remote Viewer QScopedPointer<Q3DSRemoteDeploymentManager> remote(new Q3DSRemoteDeploymentManager(engine.data())); int port = 36000; - if (cmdLineParser.isSet(QStringLiteral("connect"))) - port = cmdLineParser.value(QStringLiteral("connect")).toInt(); + if (cmdLineParser.isSet(remoteOption)) + port = cmdLineParser.value(remoteOption).toInt(); remote->setConnectionPort(port); if (fn.isEmpty()) { remote->startServer(); @@ -133,6 +131,9 @@ int main(int argc, char *argv[]) else view->show(); engine->setOnDemandRendering(true); + // in QWindow mode let F10 and double double clicks activate the + // profileui via the engine + engine->setAutoToggleProfileUi(true); } else { #ifdef Q3DSVIEWER_WIDGETS mw = new Q3DStudioMainWindow(view.take(), remote.data()); @@ -140,6 +141,9 @@ int main(int argc, char *argv[]) mw->showFullScreen(); else mw->show(); + // with widgets the engine's built-in profileui activation is not + // desirable since we have menu items with the same shortcuts (F10) + engine->setAutoToggleProfileUi(false); #endif } diff --git a/tools/q3dsviewer/q3dsmainwindow.cpp b/tools/q3dsviewer/q3dsmainwindow.cpp index ff8ec7a..e89c7b8 100644 --- a/tools/q3dsviewer/q3dsmainwindow.cpp +++ b/tools/q3dsviewer/q3dsmainwindow.cpp @@ -73,7 +73,7 @@ Q3DStudioMainWindow::Q3DStudioMainWindow(Q3DSWindow *view, Q3DSRemoteDeploymentM view->engine()->setFlag(Q3DSEngine::EnableProfiling, true); open(); } , QKeySequence::Open); - fileMenu->addAction(tr("Open without &profiling..."), this, [=] { + fileMenu->addAction(tr("Open Without &Profiling..."), this, [=] { view->engine()->setFlag(Q3DSEngine::EnableProfiling, false); open(); }); @@ -89,7 +89,7 @@ Q3DStudioMainWindow::Q3DStudioMainWindow(Q3DSWindow *view, Q3DSRemoteDeploymentM return; view->engine()->setSource(view->engine()->source()); }, QKeySequence::Refresh); - fileMenu->addAction(tr("E&xit"), this, &QWidget::close); + fileMenu->addAction(tr("E&xit"), this, &QWidget::close, QKeySequence::Quit); QMenu *viewMenu = menuBar()->addMenu(tr("&View")); if (enableDebugMenu) { @@ -107,13 +107,13 @@ Q3DStudioMainWindow::Q3DStudioMainWindow(Q3DSWindow *view, Q3DSRemoteDeploymentM }); } - viewMenu->addAction(tr("Toggle fullscree&n"), this, [this] { + viewMenu->addAction(tr("Toggle Full Scree&n"), this, [this] { Qt::WindowStates s = windowState(); s.setFlag(Qt::WindowFullScreen, !s.testFlag(Qt::WindowFullScreen)); setWindowState(s); }, QKeySequence::FullScreen); - QMenu *profileSubMenu = new QMenu(tr("&Profile and debug")); + QMenu *profileSubMenu = new QMenu(tr("&Profile and Debug")); profileSubMenu->addAction(tr("Toggle in-scene &debug view"), this, [view] { Q3DSEngine *engine = view->engine(); engine->setProfileUiVisible(!engine->isProfileUiVisible()); |