Documentation for scene graph examples.
Change-Id: Idb39fc0b6d5e538b90ae8a0b98d9f4d77e1fb617 Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
This commit is contained in:
parent
b58eb52394
commit
077ad5f304
Binary file not shown.
Before Width: | Height: | Size: 27 KiB |
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
|
@ -28,7 +28,8 @@
|
||||||
/*!
|
/*!
|
||||||
\example quick/scenegraph/customgeometry
|
\example quick/scenegraph/customgeometry
|
||||||
\title Custom Geometry Example
|
\title Custom Geometry Example
|
||||||
\ingroup examples
|
\ingroup qtquickexamples
|
||||||
|
\brief Shows how to implement a custom geometry in the Qt Quick Scene Graph.
|
||||||
|
|
||||||
\brief The custom geometry example shows how to create a QQuickItem which
|
\brief The custom geometry example shows how to create a QQuickItem which
|
||||||
uses the scene graph API to build a custom geometry for the scene
|
uses the scene graph API to build a custom geometry for the scene
|
||||||
|
@ -58,11 +59,11 @@
|
||||||
QQuickItem::updatePaintNode() which all items with custom scene
|
QQuickItem::updatePaintNode() which all items with custom scene
|
||||||
graph logic must implement.
|
graph logic must implement.
|
||||||
|
|
||||||
\e { The scene graph will on many hardware configurations be
|
\note The scene graph will on many hardware configurations be
|
||||||
rendering on a separate thread. It is therefore crucial that
|
rendering on a separate thread. It is therefore crucial that
|
||||||
interaction with the scene graph happens in a controlled
|
interaction with the scene graph happens in a controlled manner,
|
||||||
manner, first and foremost through the \l
|
first and foremost through the \l QQuickItem::updatePaintNode()
|
||||||
QQuickItem::updatePaintNode() function. }
|
function.
|
||||||
|
|
||||||
\section1 BezierCurve Implementation
|
\section1 BezierCurve Implementation
|
||||||
|
|
||||||
|
@ -122,17 +123,17 @@
|
||||||
set which has two floats, one for x coordinates and one for y
|
set which has two floats, one for x coordinates and one for y
|
||||||
coordinates. The second argument is the vertex count.
|
coordinates. The second argument is the vertex count.
|
||||||
|
|
||||||
\e {Custom attribute sets can also created, but that is not
|
Custom attribute sets can also created, but that is not
|
||||||
covered in this example}.
|
covered in this example.
|
||||||
|
|
||||||
Since we do not have any special needs for memory managing the
|
Since we do not have any special needs for memory managing the
|
||||||
geometry, we specify that the QSGGeometryNode should own the
|
geometry, we specify that the QSGGeometryNode should own the
|
||||||
geometry.
|
geometry.
|
||||||
|
|
||||||
\e {To minimize allocations, reduce memory fragmentation and
|
To minimize allocations, reduce memory fragmentation and
|
||||||
improve performance, it would also be possible to make the
|
improve performance, it would also be possible to make the
|
||||||
geometry a member of a QSGGeometryNode subclass, in which case, we
|
geometry a member of a QSGGeometryNode subclass, in which case, we
|
||||||
would not have set the QSGGeometryNode::OwnsGeometry flag}.
|
would not have set the QSGGeometryNode::OwnsGeometry flag.
|
||||||
|
|
||||||
\snippet quick/scenegraph/customgeometry/beziercurve.cpp 6
|
\snippet quick/scenegraph/customgeometry/beziercurve.cpp 6
|
||||||
|
|
||||||
|
@ -174,26 +175,32 @@
|
||||||
BezierCurve and make it part of the \c {CustomGeometry 1.0}
|
BezierCurve and make it part of the \c {CustomGeometry 1.0}
|
||||||
module.
|
module.
|
||||||
|
|
||||||
|
As the bezier curve is drawn using GL_LINE_STRIP, we specify that
|
||||||
|
the view should be multisampled to get antialiasing. This is not
|
||||||
|
required, but it will make the item look a bit nicer on hardware
|
||||||
|
that supports it. Multisampling is not enabled by default because
|
||||||
|
it often results in higher memory usage.
|
||||||
|
|
||||||
\section1 Using the Item
|
\section1 Using the Item
|
||||||
|
|
||||||
\snippet quick/scenegraph/customgeometry/LineTester.qml 1
|
\snippet quick/scenegraph/customgeometry/main.qml 1
|
||||||
|
|
||||||
Our .qml file imports the \c {QtQuick 2.0} module to get the
|
Our .qml file imports the \c {QtQuick 2.0} module to get the
|
||||||
standard elements and also our own \c {CustomGeometry 1.0} module
|
standard elements and also our own \c {CustomGeometry 1.0} module
|
||||||
which contains our newly created BezierCurve element.
|
which contains our newly created BezierCurve element.
|
||||||
|
|
||||||
\snippet quick/scenegraph/customgeometry/LineTester.qml 2
|
\snippet quick/scenegraph/customgeometry/main.qml 2
|
||||||
|
|
||||||
Then we create the our root item and an instance of the
|
Then we create the our root item and an instance of the
|
||||||
BezierCurve which we anchor to fill the root.
|
BezierCurve which we anchor to fill the root.
|
||||||
|
|
||||||
\snippet quick/scenegraph/customgeometry/LineTester.qml 3
|
\snippet quick/scenegraph/customgeometry/main.qml 3
|
||||||
|
|
||||||
To make the example a bit more interesting we add an animation to
|
To make the example a bit more interesting we add an animation to
|
||||||
change the two control points in the curve. The end points stay
|
change the two control points in the curve. The end points stay
|
||||||
unchanged.
|
unchanged.
|
||||||
|
|
||||||
\snippet quick/scenegraph/customgeometry/LineTester.qml 4
|
\snippet quick/scenegraph/customgeometry/main.qml 4
|
||||||
|
|
||||||
Finally we overlay a short text outlining what the example shows.
|
Finally we overlay a short text outlining what the example shows.
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,9 @@ int main(int argc, char **argv)
|
||||||
qmlRegisterType<BezierCurve>("CustomGeometry", 1, 0, "BezierCurve");
|
qmlRegisterType<BezierCurve>("CustomGeometry", 1, 0, "BezierCurve");
|
||||||
|
|
||||||
QQuickView view;
|
QQuickView view;
|
||||||
|
QSurfaceFormat format;
|
||||||
|
format.setSamples(16);
|
||||||
|
view.setFormat(format);
|
||||||
view.setSource(QUrl("qrc:///scenegraph/customgeometry/main.qml"));
|
view.setSource(QUrl("qrc:///scenegraph/customgeometry/main.qml"));
|
||||||
view.show();
|
view.show();
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
|
@ -0,0 +1,168 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the documentation of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $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 Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/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: http://www.gnu.org/copyleft/fdl.html.
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\example quick/scenegraph/openglunderqml
|
||||||
|
\title OpenGL Under QML
|
||||||
|
\ingroup qtquickexamples
|
||||||
|
\brief Shows how to render OpenGL under a Qt Quick scene.
|
||||||
|
|
||||||
|
\image openglunderqml-example.jpg
|
||||||
|
|
||||||
|
The OpenGL under QML example shows how an application can make use
|
||||||
|
of the \l QQuickWindow::beforeRendering() signal to draw custom
|
||||||
|
OpenGL content under a Qt Quick scene. This signal is emitted at
|
||||||
|
the start of every frame, before the scene graph starts its
|
||||||
|
rendering, thus any OpenGL draw calls that are made as a response
|
||||||
|
to this signal, will stack under the Qt Quick items.
|
||||||
|
|
||||||
|
As an alternative, applications that wish to render OpenGL content
|
||||||
|
on top of the Qt Quick scene, can do so by connecting to the \l
|
||||||
|
QQuickWindow::afterRendering() signal.
|
||||||
|
|
||||||
|
In this example, we will also see how it is possible to have
|
||||||
|
values that are exposed to QML which affect the OpenGL
|
||||||
|
rendering. We animate the threshold value using a NumberAnimation
|
||||||
|
in the QML file and this value is used by the OpenGL shader
|
||||||
|
program that draws the squircles.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.h 1
|
||||||
|
|
||||||
|
First of all, we need a QObject with a slot to connect the signals
|
||||||
|
to. We subclass QQuickItem in order to use the \l
|
||||||
|
QQuickItem::window() which holds the window instance we want to
|
||||||
|
connect to.
|
||||||
|
|
||||||
|
We use two values of \c t. The variable \c m_t is the property
|
||||||
|
value as it exists in the GUI thread. The \c m_thread_t value is a
|
||||||
|
copy of \c m_t for use in the rendering thread. We need an
|
||||||
|
explicit copy because the scene graph can render in one thread
|
||||||
|
while updating properties on the GUI thread in preparation for the
|
||||||
|
next frame. If we had used only one value, the animation could
|
||||||
|
have updated the value to that of the next frame before we got a
|
||||||
|
chance to render it.
|
||||||
|
|
||||||
|
\note In this example, a wrong value for \c t will have minimal
|
||||||
|
consequences, but we emphasize that rendering and GUI thread
|
||||||
|
objects and values must stay separate to avoid race conditions,
|
||||||
|
undesired behavior and in the worst case, crashes.
|
||||||
|
|
||||||
|
Lets move on to the implementation.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.cpp 7
|
||||||
|
|
||||||
|
The constructor of the \c Squircle class simply initializes the
|
||||||
|
values. The shader program will be initialized during rendering
|
||||||
|
later.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.cpp 8
|
||||||
|
|
||||||
|
The property setter checks that the value has indeed changed
|
||||||
|
before updating its internal variable. It then calls \l
|
||||||
|
QQuickWindow::update() which will trigger another frame to be
|
||||||
|
rendered. Note that the setter might be called during
|
||||||
|
initialization, before the object has been entered into the scene
|
||||||
|
and before it has a window.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.cpp 1
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.cpp 2
|
||||||
|
|
||||||
|
For our paint function to be called, we need to connect to the
|
||||||
|
window's signals. When Squircle object is populated into the
|
||||||
|
scene, the itemChange function is called with the change type \c
|
||||||
|
ItemSceneChange. We connect \l QQuickWindow::beforeRendering() to
|
||||||
|
\c paint() to do the rendering, and \l
|
||||||
|
QQuickWindow::beforeSynchronizing() to \c sync() to copy the state
|
||||||
|
of the \c t property for the upcoming frame.
|
||||||
|
|
||||||
|
\note Since the Squircle object has affinity to the GUI thread and
|
||||||
|
the signals are emitted from the rendering thread, it is crucial
|
||||||
|
that the connections are made with \l
|
||||||
|
Qt::DirectConnection. Failing to do so, will result in that the
|
||||||
|
slots are invoked on the wrong thread with no OpenGL context
|
||||||
|
present.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.cpp 3
|
||||||
|
|
||||||
|
The default behavior of the scene graph is to clear the
|
||||||
|
framebuffer before rendering. Since we render before the scene
|
||||||
|
graph, we need to turn this clearing off. This means that we need
|
||||||
|
to clear ourselves in the \c paint() function.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.cpp 4
|
||||||
|
|
||||||
|
The first thing we do in the \c paint() function is to
|
||||||
|
initialize the shader program. By initializing the shader program
|
||||||
|
here, we make sure that the OpenGL context is bound and that we
|
||||||
|
are on the correct thread.
|
||||||
|
|
||||||
|
We also connect to the QOpenGLContext::aboutToBeDestroyed()
|
||||||
|
signal, so that we can clean up the shader program when the
|
||||||
|
context is destroyed. Again, this is a \l Qt::DirectConnection as
|
||||||
|
all rendering related operations must happen on the rendering
|
||||||
|
thread.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.cpp 5
|
||||||
|
|
||||||
|
We use the shader program to draw the squircle. At the end of the
|
||||||
|
\c paint function we release the program and disable the
|
||||||
|
attributes we used so that the OpenGL context is in a "clean"
|
||||||
|
state for the scene graph to pick it up.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.cpp 6
|
||||||
|
|
||||||
|
In the \c cleanup() function we delete the program.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/squircle.cpp 9
|
||||||
|
|
||||||
|
We use the \c sync() function to copy the state of the
|
||||||
|
object in the GUI thread into the rendering thread.
|
||||||
|
|
||||||
|
The signal is emitted on the rendering thread while the GUI
|
||||||
|
thread is blocked, so it is safe to simply copy the value without
|
||||||
|
any additional protection.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/main.cpp 1
|
||||||
|
|
||||||
|
The application's \c main() function instantiates a QQuickView and
|
||||||
|
launches the \c main.qml file. The only thing worth noting is that
|
||||||
|
we export the \c Squircle class to QML using the \l
|
||||||
|
qmlRegisterType() macro.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/main.qml 1
|
||||||
|
|
||||||
|
We import the Squircle QML type with the name we registered in the
|
||||||
|
\c main() function. We then instantiate it and create a running
|
||||||
|
NumberAnimation on the its \c t property.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/openglunderqml/main.qml 2
|
||||||
|
|
||||||
|
Then we overlay a short descriptive text, so that it is clearly
|
||||||
|
visible that we are in fact rendering OpenGL under our Qt Quick
|
||||||
|
scene.
|
||||||
|
|
||||||
|
*/
|
|
@ -48,6 +48,8 @@
|
||||||
//! [7]
|
//! [7]
|
||||||
Squircle::Squircle()
|
Squircle::Squircle()
|
||||||
: m_program(0)
|
: m_program(0)
|
||||||
|
, m_t(0)
|
||||||
|
, m_thread_t(0)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
//! [7]
|
//! [7]
|
||||||
|
@ -70,8 +72,8 @@ void Squircle::itemChange(ItemChange change, const ItemChangeData &)
|
||||||
{
|
{
|
||||||
// The ItemSceneChange event is sent when we are first attached to a window.
|
// The ItemSceneChange event is sent when we are first attached to a window.
|
||||||
if (change == ItemSceneChange) {
|
if (change == ItemSceneChange) {
|
||||||
QQuickWindow *c = window();
|
QQuickWindow *win = window();
|
||||||
if (!c)
|
if (!win)
|
||||||
return;
|
return;
|
||||||
//! [1]
|
//! [1]
|
||||||
|
|
||||||
|
@ -79,15 +81,17 @@ void Squircle::itemChange(ItemChange change, const ItemChangeData &)
|
||||||
// Since this call is executed on the rendering thread it must be
|
// Since this call is executed on the rendering thread it must be
|
||||||
// a Qt::DirectConnection
|
// a Qt::DirectConnection
|
||||||
//! [2]
|
//! [2]
|
||||||
connect(c, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection);
|
connect(win, SIGNAL(beforeRendering()), this, SLOT(paint()), Qt::DirectConnection);
|
||||||
|
connect(win, SIGNAL(beforeSynchronizing()), this, SLOT(sync()), Qt::DirectConnection);
|
||||||
//! [2]
|
//! [2]
|
||||||
|
|
||||||
// If we allow QML to do the clearing, they would clear what we paint
|
// If we allow QML to do the clearing, they would clear what we paint
|
||||||
// and nothing would show.
|
// and nothing would show.
|
||||||
//! [3]
|
//! [3]
|
||||||
c->setClearBeforeRendering(false);
|
win->setClearBeforeRendering(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! [3] //! [4]
|
//! [3] //! [4]
|
||||||
void Squircle::paint()
|
void Squircle::paint()
|
||||||
{
|
{
|
||||||
|
@ -128,7 +132,7 @@ void Squircle::paint()
|
||||||
1, 1
|
1, 1
|
||||||
};
|
};
|
||||||
m_program->setAttributeArray(0, GL_FLOAT, values, 2);
|
m_program->setAttributeArray(0, GL_FLOAT, values, 2);
|
||||||
m_program->setUniformValue("t", (float) m_t);
|
m_program->setUniformValue("t", (float) m_thread_t);
|
||||||
|
|
||||||
glViewport(0, 0, window()->width(), window()->height());
|
glViewport(0, 0, window()->width(), window()->height());
|
||||||
|
|
||||||
|
@ -157,4 +161,10 @@ void Squircle::cleanup()
|
||||||
}
|
}
|
||||||
//! [6]
|
//! [6]
|
||||||
|
|
||||||
|
//! [9]
|
||||||
|
void Squircle::sync()
|
||||||
|
{
|
||||||
|
m_thread_t = m_t;
|
||||||
|
}
|
||||||
|
//! [9]
|
||||||
|
|
||||||
|
|
|
@ -67,11 +67,13 @@ protected:
|
||||||
public slots:
|
public slots:
|
||||||
void paint();
|
void paint();
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
void sync();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QOpenGLShaderProgram *m_program;
|
QOpenGLShaderProgram *m_program;
|
||||||
|
|
||||||
qreal m_t;
|
qreal m_t;
|
||||||
|
qreal m_thread_t;
|
||||||
};
|
};
|
||||||
//! [1]
|
//! [1]
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
|
@ -0,0 +1,180 @@
|
||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** This file is part of the documentation of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $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 Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/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: http://www.gnu.org/copyleft/fdl.html.
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\example quick/scenegraph/simplematerial
|
||||||
|
\title Simple Material Example
|
||||||
|
\ingroup qtquickexamples
|
||||||
|
\brief Shows how to define a scene graph material to fill a shape.
|
||||||
|
|
||||||
|
\image simplematerial-example.jpg
|
||||||
|
|
||||||
|
In this example, we will make use of the \l
|
||||||
|
QSGSimpleMaterialShader class to fill a shape in the scene
|
||||||
|
graph. This is a convenience class intended to avoid a lot of the
|
||||||
|
boilerplate code required when creating materials with the \l
|
||||||
|
QSGMaterial, \l QSGMaterialShader and \l QSGMaterialType classes
|
||||||
|
directly.
|
||||||
|
|
||||||
|
A simple material consists of two parts, the material state and
|
||||||
|
the material shader. The material shader has one instance per
|
||||||
|
scene graph and contains the actual OpenGL shader program and
|
||||||
|
information about which attributes and uniforms it uses. The
|
||||||
|
material state is what we assign to each individual node, in this
|
||||||
|
case to give them different colors.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 1
|
||||||
|
|
||||||
|
The first thing we do when creating custom materials with the
|
||||||
|
simplified scheme is to create a state class. In this case the
|
||||||
|
state class contains only one member, a QColor. It also defines a
|
||||||
|
compare function which the scene graph can use to reorder the node
|
||||||
|
rendering.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 2
|
||||||
|
|
||||||
|
Next we define the material shader, by subclassing a template
|
||||||
|
instantiation of \l QSGSimpleMaterialShader with our \c State.
|
||||||
|
|
||||||
|
Then we use the macro \l QSG_DECLARE_SIMPLE_COMPARABLE_SHADER()
|
||||||
|
which will generate some boilerplate code for us. Since our \c
|
||||||
|
State class has a compare function, we declare that the states can
|
||||||
|
be compared. It would have been possible to remove the \c
|
||||||
|
State::compare() function and instead declare the shader with \l
|
||||||
|
QSG_DECLARE_SIMPLE_SHADER(), but this could then reduce performance
|
||||||
|
in certain usecases.
|
||||||
|
|
||||||
|
The state struct is used as a template parameter to
|
||||||
|
automatically generate a \l QSGMaterialType for us, so it is
|
||||||
|
crucial that the pair of shader and state are made up of unique
|
||||||
|
classes. Using the same \c State class in multiple shaders will
|
||||||
|
will lead to undefined behavior.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 3
|
||||||
|
|
||||||
|
Next comes the declaration of the shader source code, where we
|
||||||
|
define a vertex and fragment shader. The simple material assumes
|
||||||
|
the presence of \c qt_Matrix in the vertex shader and \c
|
||||||
|
qt_Opacity in the fragment shader.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 4
|
||||||
|
|
||||||
|
We reimplement the \c attributes function to return the name of
|
||||||
|
the \c aVertex and \c aTexCoord attribute names. These attributes
|
||||||
|
will be mapped to attribute indices 0 and 1 in the node's
|
||||||
|
geometry.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 6
|
||||||
|
|
||||||
|
Uniforms can be accessed either by name or by index, where index
|
||||||
|
is faster than name, so we reimplement the \c resolveUniforms()
|
||||||
|
function to find the index of the \c color uniform. We do not have
|
||||||
|
to worry about resolving \c qt_Opacity or \c qt_Matrix as these
|
||||||
|
are handled by the baseclass.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 5
|
||||||
|
|
||||||
|
The \c updateState() function is called once for every unique
|
||||||
|
state and we use it to update the shader program with the current
|
||||||
|
color. The previous state is passed in as a second parameter so
|
||||||
|
that the user can update only that which has changed. In our
|
||||||
|
usecase, where all the colors are different, the updateState will
|
||||||
|
be called once for every node.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 7
|
||||||
|
|
||||||
|
The \c ColorNode class is supposed to draw something, so it needs
|
||||||
|
to be a subclass of \l QSGGeometryNode.
|
||||||
|
|
||||||
|
Since our shader expects both a position and a texture coordinate,
|
||||||
|
we use the default attribute set \l
|
||||||
|
QSGGeometry::defaultAttributes_TexturedPoint2D() and define that
|
||||||
|
the geometry consists of a total of four vertices. To avoid the
|
||||||
|
allocation, we make the QSGGeometry a member of the
|
||||||
|
QSGGeometryNode.
|
||||||
|
|
||||||
|
When used the macro \l QSG_DECLARE_SIMPLE_COMPARABLE_SHADER() above,
|
||||||
|
it defined the \c createMaterial() function which we use to
|
||||||
|
instantiate materials for our \c State struct.
|
||||||
|
|
||||||
|
As we will be making use of opacity in our custom material, we
|
||||||
|
need to set the \l QSGMaterial::Blending flag. The scene graph may
|
||||||
|
use this flag to either disable or enable \c GL_BLEND when drawing
|
||||||
|
the node or to reorder the drawing of the node.
|
||||||
|
|
||||||
|
Finally, we tell the node to take ownership of the material, so we
|
||||||
|
do not have to explicitly memorymanage it.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 8
|
||||||
|
|
||||||
|
Since the Item is providing its own graphics to the scene graph,
|
||||||
|
we set the flag \l QQuickItem::ItemHasContents.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 9
|
||||||
|
|
||||||
|
Whenever the Item has changed graphically, the \l
|
||||||
|
QQuickItem::updatePaintNode() function is called.
|
||||||
|
|
||||||
|
\note The scene graph may be rendered in a different thread than the
|
||||||
|
GUI thread and \l QQuickItem::updatePaintNode() is one of the few
|
||||||
|
places where it is safe to access properties of the QML
|
||||||
|
object. Any interaction with the scene graph from a custom \l
|
||||||
|
QQuickItem should be contained to this function. The function is
|
||||||
|
called on the rendering thread while the GUI thread is blocked.
|
||||||
|
|
||||||
|
The first time this function is called for an \c Item instance,
|
||||||
|
the node will be 0 and we create a new one. For every consecutive
|
||||||
|
call, the node will be what we returned previously. There are
|
||||||
|
scenarios where the scene graph will be removed and rebuilt from
|
||||||
|
scratch however, so one should always check the node and recreate
|
||||||
|
it if required.
|
||||||
|
|
||||||
|
Once we have a \c ColorNode, we update its geometry and material
|
||||||
|
state. Finally, we notify the scene graph that the node has
|
||||||
|
undergone changes to its geometry and material.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/simplematerial.cpp 11
|
||||||
|
|
||||||
|
The \c main() function of the application adds the custom QML type
|
||||||
|
using \l qmlRegisterType() and opens up a \l QQuickView with our
|
||||||
|
QML file.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/main.qml 1
|
||||||
|
|
||||||
|
In the QML file, we import our custom type so we can instantiate
|
||||||
|
it.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/main.qml 2
|
||||||
|
|
||||||
|
Then we create a column of three instances of our custom item,
|
||||||
|
each with a different color.
|
||||||
|
|
||||||
|
\snippet quick/scenegraph/simplematerial/main.qml 3
|
||||||
|
|
||||||
|
And finally we overlay a short descriptive text.
|
||||||
|
|
||||||
|
*/
|
|
@ -44,30 +44,40 @@ import QtQuick 2.0
|
||||||
import SimpleMaterial 1.0
|
import SimpleMaterial 1.0
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
width: 640
|
width: 320
|
||||||
height: 360
|
height: 480
|
||||||
|
color: "black"
|
||||||
gradient: Gradient {
|
|
||||||
GradientStop { position: 0; color: "#00ffff" }
|
|
||||||
GradientStop { position: 1; color: "#00ff00" }
|
|
||||||
}
|
|
||||||
|
|
||||||
//! [1] //! [2]
|
//! [1] //! [2]
|
||||||
SimpleMaterialItem {
|
|
||||||
|
|
||||||
|
Column {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
SequentialAnimation on scale {
|
|
||||||
NumberAnimation { to: 100; duration: 60000; easing.type: Easing.InCubic }
|
SimpleMaterialItem {
|
||||||
NumberAnimation { to: 1; duration: 60000; easing.type: Easing.OutCubic }
|
width: parent.width;
|
||||||
loops: Animation.Infinite
|
height: parent.height / 3;
|
||||||
|
color: "steelblue"
|
||||||
}
|
}
|
||||||
|
|
||||||
rotation: scale * 10 - 10
|
SimpleMaterialItem {
|
||||||
|
width: parent.width;
|
||||||
|
height: parent.height / 3;
|
||||||
|
color: "darkorchid"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SimpleMaterialItem {
|
||||||
|
width: parent.width;
|
||||||
|
height: parent.height / 3;
|
||||||
|
color: "springgreen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//! [2] //! [3]
|
//! [2] //! [3]
|
||||||
Rectangle {
|
Rectangle {
|
||||||
color: Qt.rgba(0, 0, 0, 0.8)
|
color: Qt.rgba(0, 0, 0, 0.8)
|
||||||
radius: 10
|
radius: 10
|
||||||
|
antialiasing: true
|
||||||
border.width: 1
|
border.width: 1
|
||||||
border.color: "black"
|
border.color: "black"
|
||||||
anchors.fill: label
|
anchors.fill: label
|
||||||
|
@ -78,7 +88,7 @@ Rectangle {
|
||||||
id: label
|
id: label
|
||||||
color: "white"
|
color: "white"
|
||||||
wrapMode: Text.WordWrap
|
wrapMode: Text.WordWrap
|
||||||
text: "The background here is implemented as one QSGGeometryNode node which uses QSGSimpleMaterial to implement a mandlebrot fractal fill"
|
text: "These three gradient boxes are colorized using a custom material."
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
|
|
|
@ -52,11 +52,11 @@
|
||||||
#include <qsgsimplematerial.h>
|
#include <qsgsimplematerial.h>
|
||||||
|
|
||||||
//! [1]
|
//! [1]
|
||||||
struct Color
|
struct State
|
||||||
{
|
{
|
||||||
QColor color;
|
QColor color;
|
||||||
|
|
||||||
int compare(const Color *other) const {
|
int compare(const State *other) const {
|
||||||
uint rgb = color.rgba();
|
uint rgb = color.rgba();
|
||||||
uint otherRgb = other->color.rgba();
|
uint otherRgb = other->color.rgba();
|
||||||
|
|
||||||
|
@ -72,9 +72,9 @@ struct Color
|
||||||
//! [1]
|
//! [1]
|
||||||
|
|
||||||
//! [2]
|
//! [2]
|
||||||
class Shader : public QSGSimpleMaterialShader<Color>
|
class Shader : public QSGSimpleMaterialShader<State>
|
||||||
{
|
{
|
||||||
QSG_DECLARE_SIMPLE_COMPARABLE_SHADER(Shader, Color);
|
QSG_DECLARE_SIMPLE_COMPARABLE_SHADER(Shader, State);
|
||||||
//! [2] //! [3]
|
//! [2] //! [3]
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
@ -97,18 +97,8 @@ public:
|
||||||
"varying highp vec2 texCoord; \n"
|
"varying highp vec2 texCoord; \n"
|
||||||
"void main () \n"
|
"void main () \n"
|
||||||
"{ \n"
|
"{ \n"
|
||||||
" highp vec2 z = texCoord; \n"
|
" gl_FragColor = texCoord.y * texCoord.x * color * qt_Opacity; \n"
|
||||||
" gl_FragColor = vec4(0); \n"
|
"}";
|
||||||
" const highp float maxIterations = 100.; \n"
|
|
||||||
" for (float i = 0.; i < maxIterations; i += 1.0) { \n"
|
|
||||||
" z = vec2(z.x*z.x - z.y*z.y, 2.0*z.x*z.y) + texCoord; \n"
|
|
||||||
" if (dot(z, z) > 4.0) { \n"
|
|
||||||
" float col = pow(1. - i / maxIterations, sqrt(maxIterations / 10.)); \n"
|
|
||||||
" gl_FragColor = color * col * qt_Opacity; \n"
|
|
||||||
" break; \n"
|
|
||||||
" } \n"
|
|
||||||
" } \n"
|
|
||||||
"} \n";
|
|
||||||
}
|
}
|
||||||
//! [3] //! [4]
|
//! [3] //! [4]
|
||||||
QList<QByteArray> attributes() const
|
QList<QByteArray> attributes() const
|
||||||
|
@ -116,9 +106,9 @@ public:
|
||||||
return QList<QByteArray>() << "aVertex" << "aTexCoord";
|
return QList<QByteArray>() << "aVertex" << "aTexCoord";
|
||||||
}
|
}
|
||||||
//! [4] //! [5]
|
//! [4] //! [5]
|
||||||
void updateState(const Color *color, const Color *)
|
void updateState(const State *state, const State *)
|
||||||
{
|
{
|
||||||
program()->setUniformValue(id_color, color->color);
|
program()->setUniformValue(id_color, state->color);
|
||||||
}
|
}
|
||||||
//! [5] //! [6]
|
//! [5] //! [6]
|
||||||
void resolveUniforms()
|
void resolveUniforms()
|
||||||
|
@ -128,38 +118,37 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int id_color;
|
int id_color;
|
||||||
};
|
|
||||||
//! [6]
|
//! [6]
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
//! [7]
|
//! [7]
|
||||||
class TestNode : public QSGGeometryNode
|
class ColorNode : public QSGGeometryNode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TestNode(const QRectF &bounds)
|
ColorNode()
|
||||||
: m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
|
: m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4)
|
||||||
{
|
{
|
||||||
QSGGeometry::updateTexturedRectGeometry(&m_geometry, bounds, QRectF(-0.60, -0.66, 0.08, 0.04));
|
|
||||||
setGeometry(&m_geometry);
|
setGeometry(&m_geometry);
|
||||||
|
|
||||||
//! [7] //! [8]
|
QSGSimpleMaterial<State> *material = Shader::createMaterial();
|
||||||
QSGSimpleMaterial<Color> *material = Shader::createMaterial();
|
|
||||||
material->state()->color = Qt::blue;
|
|
||||||
material->setFlag(QSGMaterial::Blending);
|
material->setFlag(QSGMaterial::Blending);
|
||||||
|
|
||||||
setMaterial(material);
|
setMaterial(material);
|
||||||
setFlag(OwnsMaterial);
|
setFlag(OwnsMaterial);
|
||||||
}
|
}
|
||||||
//! [8] //! [9]
|
|
||||||
QSGGeometry m_geometry;
|
QSGGeometry m_geometry;
|
||||||
};
|
};
|
||||||
//! [9]
|
//! [7]
|
||||||
|
|
||||||
|
|
||||||
//! [10]
|
//! [8]
|
||||||
class Item : public QQuickItem
|
class Item : public QQuickItem
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
|
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Item()
|
Item()
|
||||||
|
@ -167,17 +156,40 @@ public:
|
||||||
setFlag(ItemHasContents, true);
|
setFlag(ItemHasContents, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setColor(const QColor &color) {
|
||||||
|
if (m_color != color) {
|
||||||
|
m_color = color;
|
||||||
|
emit colorChanged();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
QColor color() const {
|
||||||
|
return m_color;
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void colorChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QColor m_color;
|
||||||
|
|
||||||
|
//! [8] //! [9]
|
||||||
|
public:
|
||||||
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
|
QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *)
|
||||||
{
|
{
|
||||||
delete node;
|
ColorNode *n = static_cast<ColorNode *>(node);
|
||||||
return new TestNode(boundingRect());
|
if (!node)
|
||||||
|
n = new ColorNode();
|
||||||
|
|
||||||
|
QSGGeometry::updateTexturedRectGeometry(n->geometry(), boundingRect(), QRectF(0, 0, 1, 1));
|
||||||
|
static_cast<QSGSimpleMaterial<State>*>(n->material())->state()->color = m_color;
|
||||||
|
|
||||||
|
n->markDirty(QSGNode::DirtyGeometry | QSGNode::DirtyMaterial);
|
||||||
|
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
//! [10]
|
//! [9] //! [11]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//! [11]
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
QGuiApplication app(argc, argv);
|
QGuiApplication app(argc, argv);
|
||||||
|
@ -185,11 +197,12 @@ int main(int argc, char **argv)
|
||||||
qmlRegisterType<Item>("SimpleMaterial", 1, 0, "SimpleMaterialItem");
|
qmlRegisterType<Item>("SimpleMaterial", 1, 0, "SimpleMaterialItem");
|
||||||
|
|
||||||
QQuickView view;
|
QQuickView view;
|
||||||
|
view.setResizeMode(QQuickView::SizeRootObjectToView);
|
||||||
view.setSource(QUrl("qrc:///scenegraph/simplematerial/main.qml"));
|
view.setSource(QUrl("qrc:///scenegraph/simplematerial/main.qml"));
|
||||||
view.show();
|
view.show();
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
//! [11]
|
|
||||||
|
|
||||||
#include "simplematerial.moc"
|
#include "simplematerial.moc"
|
||||||
|
//! [11]
|
||||||
|
|
|
@ -144,6 +144,29 @@
|
||||||
\sa {Simple Material Example}
|
\sa {Simple Material Example}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\macro QSG_DECLARE_SIMPLE_SHADER(Shader, State)
|
||||||
|
\relates QSGSimpleMaterialShader
|
||||||
|
|
||||||
|
This macro is used to declare a QSGMaterialType and a \c
|
||||||
|
createMaterial() function for \a Shader with the given \a State.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\macro QSG_DECLARE_SIMPLE_COMPARABLE_SHADER(Shader, State)
|
||||||
|
\relates QSGSimpleMaterialShader
|
||||||
|
|
||||||
|
This macro is used to declare a QSGMaterialType and a \c
|
||||||
|
createMaterial() function for \a Shader with the given \a State,
|
||||||
|
where the \a State class must define a compare function on the
|
||||||
|
form:
|
||||||
|
|
||||||
|
\code
|
||||||
|
int compare(const State *other) const;
|
||||||
|
\endcode
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\fn char const *const *QSGSimpleMaterialShader::attributeNames() const
|
\fn char const *const *QSGSimpleMaterialShader::attributeNames() const
|
||||||
\internal
|
\internal
|
||||||
|
|
Loading…
Reference in New Issue