diff options
Diffstat (limited to 'examples/quick/scenegraph/simplematerial')
-rw-r--r-- | examples/quick/scenegraph/simplematerial/doc/images/simplematerial-example.jpg | bin | 0 -> 10744 bytes | |||
-rw-r--r-- | examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc | 180 | ||||
-rw-r--r-- | examples/quick/scenegraph/simplematerial/main.qml | 40 | ||||
-rw-r--r-- | examples/quick/scenegraph/simplematerial/simplematerial.cpp | 87 |
4 files changed, 255 insertions, 52 deletions
diff --git a/examples/quick/scenegraph/simplematerial/doc/images/simplematerial-example.jpg b/examples/quick/scenegraph/simplematerial/doc/images/simplematerial-example.jpg Binary files differnew file mode 100644 index 0000000000..08db8dee4e --- /dev/null +++ b/examples/quick/scenegraph/simplematerial/doc/images/simplematerial-example.jpg diff --git a/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc new file mode 100644 index 0000000000..20d244fe99 --- /dev/null +++ b/examples/quick/scenegraph/simplematerial/doc/src/simplematerial.qdoc @@ -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. + + */ diff --git a/examples/quick/scenegraph/simplematerial/main.qml b/examples/quick/scenegraph/simplematerial/main.qml index 70771a7c35..cc34fe605e 100644 --- a/examples/quick/scenegraph/simplematerial/main.qml +++ b/examples/quick/scenegraph/simplematerial/main.qml @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the demonstration applications of the Qt Toolkit. @@ -44,30 +44,40 @@ import QtQuick 2.0 import SimpleMaterial 1.0 Rectangle { - width: 640 - height: 360 - - gradient: Gradient { - GradientStop { position: 0; color: "#00ffff" } - GradientStop { position: 1; color: "#00ff00" } - } + width: 320 + height: 480 + color: "black" //! [1] //! [2] - SimpleMaterialItem { + Column { anchors.fill: parent - SequentialAnimation on scale { - NumberAnimation { to: 100; duration: 60000; easing.type: Easing.InCubic } - NumberAnimation { to: 1; duration: 60000; easing.type: Easing.OutCubic } - loops: Animation.Infinite + + SimpleMaterialItem { + width: parent.width; + height: parent.height / 3; + color: "steelblue" + } + + SimpleMaterialItem { + width: parent.width; + height: parent.height / 3; + color: "darkorchid" } - rotation: scale * 10 - 10 + SimpleMaterialItem { + width: parent.width; + height: parent.height / 3; + color: "springgreen" + } } + + //! [2] //! [3] Rectangle { color: Qt.rgba(0, 0, 0, 0.8) radius: 10 + antialiasing: true border.width: 1 border.color: "black" anchors.fill: label @@ -78,7 +88,7 @@ Rectangle { id: label color: "white" 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.left: parent.left anchors.bottom: parent.bottom diff --git a/examples/quick/scenegraph/simplematerial/simplematerial.cpp b/examples/quick/scenegraph/simplematerial/simplematerial.cpp index b7bea08260..f863c78b79 100644 --- a/examples/quick/scenegraph/simplematerial/simplematerial.cpp +++ b/examples/quick/scenegraph/simplematerial/simplematerial.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies). +** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). ** Contact: http://www.qt-project.org/legal ** ** This file is part of the demonstration applications of the Qt Toolkit. @@ -52,11 +52,11 @@ #include <qsgsimplematerial.h> //! [1] -struct Color +struct State { QColor color; - int compare(const Color *other) const { + int compare(const State *other) const { uint rgb = color.rgba(); uint otherRgb = other->color.rgba(); @@ -72,9 +72,9 @@ struct Color //! [1] //! [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] public: @@ -97,18 +97,8 @@ public: "varying highp vec2 texCoord; \n" "void main () \n" "{ \n" - " highp vec2 z = texCoord; \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"; + " gl_FragColor = texCoord.y * texCoord.x * color * qt_Opacity; \n" + "}"; } //! [3] //! [4] QList<QByteArray> attributes() const @@ -116,9 +106,9 @@ public: return QList<QByteArray>() << "aVertex" << "aTexCoord"; } //! [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] void resolveUniforms() @@ -128,38 +118,37 @@ public: private: int id_color; -}; //! [6] +}; //! [7] -class TestNode : public QSGGeometryNode +class ColorNode : public QSGGeometryNode { public: - TestNode(const QRectF &bounds) + ColorNode() : m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 4) { - QSGGeometry::updateTexturedRectGeometry(&m_geometry, bounds, QRectF(-0.60, -0.66, 0.08, 0.04)); setGeometry(&m_geometry); -//! [7] //! [8] - QSGSimpleMaterial<Color> *material = Shader::createMaterial(); - material->state()->color = Qt::blue; + QSGSimpleMaterial<State> *material = Shader::createMaterial(); material->setFlag(QSGMaterial::Blending); - setMaterial(material); setFlag(OwnsMaterial); } -//! [8] //! [9] + QSGGeometry m_geometry; }; -//! [9] +//! [7] -//! [10] +//! [8] class Item : public QQuickItem { Q_OBJECT + + Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) + public: Item() @@ -167,17 +156,40 @@ public: 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 *) { - delete node; - return new TestNode(boundingRect()); - } -}; -//! [10] + ColorNode *n = static_cast<ColorNode *>(node); + 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); -//! [11] + return n; + } +}; +//! [9] //! [11] int main(int argc, char **argv) { QGuiApplication app(argc, argv); @@ -185,11 +197,12 @@ int main(int argc, char **argv) qmlRegisterType<Item>("SimpleMaterial", 1, 0, "SimpleMaterialItem"); QQuickView view; + view.setResizeMode(QQuickView::SizeRootObjectToView); view.setSource(QUrl("qrc:///scenegraph/simplematerial/main.qml")); view.show(); return app.exec(); } -//! [11] #include "simplematerial.moc" +//! [11] |