/usr/share/qt5/doc/qtquick/qtquick-scenegraph-simplematerial-example.html is in qtdeclarative5-doc-html 5.9.5-0ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 | <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- simplematerial.qdoc -->
<title>Scene Graph - Simple Material | Qt Quick 5.9</title>
<link rel="stylesheet" type="text/css" href="style/offline-simple.css" />
<script type="text/javascript">
document.getElementsByTagName("link").item(0).setAttribute("href", "style/offline.css");
// loading style sheet breaks anchors that were jumped to before
// so force jumping to anchor again
setTimeout(function() {
var anchor = location.hash;
// need to jump to different anchor first (e.g. none)
location.hash = "#";
setTimeout(function() {
location.hash = anchor;
}, 0);
}, 0);
</script>
</head>
<body>
<div class="header" id="qtdocheader">
<div class="main">
<div class="main-rounded">
<div class="navigationbar">
<table><tr>
<td >Qt 5.9</td><td ><a href="qtquick-index.html">Qt Quick</a></td><td >Scene Graph - Simple Material</td></tr></table><table class="buildversion"><tr>
<td id="buildversion" width="100%" align="right">Qt 5.9.5 Reference Documentation</td>
</tr></table>
</div>
</div>
<div class="content">
<div class="line">
<div class="content mainContent">
<div class="sidebar"><div class="sidebar-content" id="sidebar-content"></div></div>
<h1 class="title">Scene Graph - Simple Material</h1>
<span class="subtitle"></span>
<!-- $$$scenegraph/simplematerial-description -->
<div class="descr"> <a name="details"></a>
<p class="centerAlign"><img src="images/simplematerial-example.jpg" alt="" /></p><p>In this example, we will make use of the <a href="qsgsimplematerialshader.html">QSGSimpleMaterialShader</a> 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 <a href="qsgmaterial.html">QSGMaterial</a>, <a href="qsgmaterialshader.html">QSGMaterialShader</a> and <a href="qsgmaterialtype.html">QSGMaterialType</a> classes directly.</p>
<p>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.</p>
<pre class="cpp">
<span class="keyword">struct</span> State
{
<span class="type"><a href="../qtgui/qcolor.html">QColor</a></span> color;
<span class="type">int</span> compare(<span class="keyword">const</span> State <span class="operator">*</span>other) <span class="keyword">const</span> {
<span class="type"><a href="../qtcore/qtglobal.html#uint-typedef">uint</a></span> rgb <span class="operator">=</span> color<span class="operator">.</span>rgba();
<span class="type"><a href="../qtcore/qtglobal.html#uint-typedef">uint</a></span> otherRgb <span class="operator">=</span> other<span class="operator">-</span><span class="operator">></span>color<span class="operator">.</span>rgba();
<span class="keyword">if</span> (rgb <span class="operator">=</span><span class="operator">=</span> otherRgb) {
<span class="keyword">return</span> <span class="number">0</span>;
} <span class="keyword">else</span> <span class="keyword">if</span> (rgb <span class="operator"><</span> otherRgb) {
<span class="keyword">return</span> <span class="operator">-</span><span class="number">1</span>;
} <span class="keyword">else</span> {
<span class="keyword">return</span> <span class="number">1</span>;
}
}
};
</pre>
<p>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 <a href="../qtgui/qcolor.html">QColor</a>. It also defines a compare function which the scene graph can use to reorder the node rendering.</p>
<pre class="cpp">
<span class="keyword">class</span> Shader : <span class="keyword">public</span> <span class="type"><a href="qsgsimplematerialshader.html">QSGSimpleMaterialShader</a></span><span class="operator"><</span>State<span class="operator">></span>
{
QSG_DECLARE_SIMPLE_COMPARABLE_SHADER(Shader<span class="operator">,</span> State);
</pre>
<p>Next we define the material shader, by subclassing a template instantiation of <a href="qsgsimplematerialshader.html">QSGSimpleMaterialShader</a> with our <code>State</code>.</p>
<p>Then we use the macro <a href="qsgsimplematerialshader.html#QSG_DECLARE_SIMPLE_COMPARABLE_SHADER">QSG_DECLARE_SIMPLE_COMPARABLE_SHADER</a>() which will generate some boilerplate code for us. Since our <code>State</code> class has a compare function, we declare that the states can be compared. It would have been possible to remove the <code>State::compare()</code> function and instead declare the shader with <a href="qsgsimplematerialshader.html#QSG_DECLARE_SIMPLE_SHADER">QSG_DECLARE_SIMPLE_SHADER</a>(), but this could then reduce performance in certain use cases.</p>
<p>The state struct is used as a template parameter to automatically generate a <a href="qsgmaterialtype.html">QSGMaterialType</a> for us, so it is crucial that the pair of shader and state are made up of unique classes. Using the same <code>State</code> class in multiple shaders will will lead to undefined behavior.</p>
<pre class="cpp">
<span class="keyword">public</span>:
<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>vertexShader() <span class="keyword">const</span> {
<span class="keyword">return</span>
<span class="string">"attribute highp vec4 aVertex; \n"</span>
<span class="string">"attribute highp vec2 aTexCoord; \n"</span>
<span class="string">"uniform highp mat4 qt_Matrix; \n"</span>
<span class="string">"varying highp vec2 texCoord; \n"</span>
<span class="string">"void main() { \n"</span>
<span class="string">" gl_Position = qt_Matrix * aVertex; \n"</span>
<span class="string">" texCoord = aTexCoord; \n"</span>
<span class="string">"}"</span>;
}
<span class="keyword">const</span> <span class="type">char</span> <span class="operator">*</span>fragmentShader() <span class="keyword">const</span> {
<span class="keyword">return</span>
<span class="string">"uniform lowp float qt_Opacity; \n"</span>
<span class="string">"uniform lowp vec4 color; \n"</span>
<span class="string">"varying highp vec2 texCoord; \n"</span>
<span class="string">"void main () \n"</span>
<span class="string">"{ \n"</span>
<span class="string">" gl_FragColor = texCoord.y * texCoord.x * color * qt_Opacity; \n"</span>
<span class="string">"}"</span>;
}
</pre>
<p>Next comes the declaration of the shader source code, where we define a vertex and fragment shader. The simple material assumes the presence of <code>qt_Matrix</code> in the vertex shader and <code>qt_Opacity</code> in the fragment shader.</p>
<pre class="cpp">
<span class="type"><a href="../qtcore/qlist.html">QList</a></span><span class="operator"><</span><span class="type"><a href="../qtcore/qbytearray.html">QByteArray</a></span><span class="operator">></span> attributes() <span class="keyword">const</span>
{
<span class="keyword">return</span> <span class="type"><a href="../qtcore/qlist.html">QList</a></span><span class="operator"><</span><span class="type"><a href="../qtcore/qbytearray.html">QByteArray</a></span><span class="operator">></span>() <span class="operator"><</span><span class="operator"><</span> <span class="string">"aVertex"</span> <span class="operator"><</span><span class="operator"><</span> <span class="string">"aTexCoord"</span>;
}
</pre>
<p>We reimplement the <code>attributes</code> function to return the name of the <code>aVertex</code> and <code>aTexCoord</code> attributes. These attributes will be mapped to attribute indices 0 and 1 in the node's geometry.</p>
<pre class="cpp">
<span class="type">void</span> resolveUniforms()
{
id_color <span class="operator">=</span> program()<span class="operator">-</span><span class="operator">></span>uniformLocation(<span class="string">"color"</span>);
}
<span class="keyword">private</span>:
<span class="type">int</span> id_color;
</pre>
<p>Uniforms can be accessed either by name or by index, where index is faster than name. We reimplement the <code>resolveUniforms()</code> function to find the index of the <code>color</code> uniform. We do not have to worry about resolving <code>qt_Opacity</code> or <code>qt_Matrix</code> as these are handled by the baseclass.</p>
<pre class="cpp">
<span class="type">void</span> updateState(<span class="keyword">const</span> State <span class="operator">*</span>state<span class="operator">,</span> <span class="keyword">const</span> State <span class="operator">*</span>)
{
program()<span class="operator">-</span><span class="operator">></span>setUniformValue(id_color<span class="operator">,</span> state<span class="operator">-</span><span class="operator">></span>color);
}
</pre>
<p>The <code>updateState()</code> 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 use case, where all the colors are different, the updateState() function will be called once for every node.</p>
<pre class="cpp">
<span class="keyword">class</span> ColorNode : <span class="keyword">public</span> <span class="type"><a href="qsggeometrynode.html">QSGGeometryNode</a></span>
{
<span class="keyword">public</span>:
ColorNode()
: m_geometry(<span class="type"><a href="qsggeometry.html">QSGGeometry</a></span><span class="operator">::</span>defaultAttributes_TexturedPoint2D()<span class="operator">,</span> <span class="number">4</span>)
{
setGeometry(<span class="operator">&</span>m_geometry);
<span class="type"><a href="qsgsimplematerial.html">QSGSimpleMaterial</a></span><span class="operator"><</span>State<span class="operator">></span> <span class="operator">*</span>material <span class="operator">=</span> Shader<span class="operator">::</span>createMaterial();
material<span class="operator">-</span><span class="operator">></span>setFlag(<span class="type"><a href="qsgmaterial.html">QSGMaterial</a></span><span class="operator">::</span>Blending);
setMaterial(material);
setFlag(OwnsMaterial);
}
<span class="type"><a href="qsggeometry.html">QSGGeometry</a></span> m_geometry;
};
</pre>
<p>The <code>ColorNode</code> class is supposed to draw something, so it needs to be a subclass of <a href="qsggeometrynode.html">QSGGeometryNode</a>.</p>
<p>Since our shader expects both a position and a texture coordinate, we use the default attribute set <a href="qsggeometry.html#defaultAttributes_TexturedPoint2D">QSGGeometry::defaultAttributes_TexturedPoint2D</a>() and declare that the geometry consists of a total of four vertices. To avoid the allocation, we make the <a href="qsggeometry.html">QSGGeometry</a> a member of the <a href="qsggeometrynode.html">QSGGeometryNode</a>.</p>
<p>When we used the macro <a href="qsgsimplematerialshader.html#QSG_DECLARE_SIMPLE_COMPARABLE_SHADER">QSG_DECLARE_SIMPLE_COMPARABLE_SHADER</a>() above, it defined the <code>createMaterial()</code> function which we use to instantiate materials for our <code>State</code> struct.</p>
<p>As we will be making use of opacity in our custom material, we need to set the <a href="qsgmaterial.html#Flag-enum">QSGMaterial::Blending</a> flag. The scene graph may use this flag to either disable or enable <code>GL_BLEND</code> when drawing the node or to reorder the drawing of the node.</p>
<p>Finally, we tell the node to take ownership of the material, so we do not have to explicitly memory-manage it.</p>
<pre class="cpp">
<span class="keyword">class</span> Item : <span class="keyword">public</span> <span class="type"><a href="qquickitem.html">QQuickItem</a></span>
{
Q_OBJECT
Q_PROPERTY(<span class="type"><a href="../qtgui/qcolor.html">QColor</a></span> color READ color WRITE setColor NOTIFY colorChanged)
<span class="keyword">public</span>:
Item()
{
setFlag(ItemHasContents<span class="operator">,</span> <span class="keyword">true</span>);
}
<span class="type">void</span> setColor(<span class="keyword">const</span> <span class="type"><a href="../qtgui/qcolor.html">QColor</a></span> <span class="operator">&</span>color) {
<span class="keyword">if</span> (m_color <span class="operator">!</span><span class="operator">=</span> color) {
m_color <span class="operator">=</span> color;
<span class="keyword">emit</span> colorChanged();
update();
}
}
<span class="type"><a href="../qtgui/qcolor.html">QColor</a></span> color() <span class="keyword">const</span> {
<span class="keyword">return</span> m_color;
}
<span class="keyword">signals</span>:
<span class="type">void</span> colorChanged();
<span class="keyword">private</span>:
<span class="type"><a href="../qtgui/qcolor.html">QColor</a></span> m_color;
</pre>
<p>Since the Item is providing its own graphics to the scene graph, we set the flag <a href="qquickitem.html#Flag-enum">QQuickItem::ItemHasContents</a>.</p>
<pre class="cpp">
<span class="keyword">public</span>:
<span class="type"><a href="qsgnode.html">QSGNode</a></span> <span class="operator">*</span>updatePaintNode(<span class="type"><a href="qsgnode.html">QSGNode</a></span> <span class="operator">*</span>node<span class="operator">,</span> UpdatePaintNodeData <span class="operator">*</span>)
{
ColorNode <span class="operator">*</span>n <span class="operator">=</span> <span class="keyword">static_cast</span><span class="operator"><</span>ColorNode <span class="operator">*</span><span class="operator">></span>(node);
<span class="keyword">if</span> (<span class="operator">!</span>node)
n <span class="operator">=</span> <span class="keyword">new</span> ColorNode();
<span class="type"><a href="qsggeometry.html">QSGGeometry</a></span><span class="operator">::</span>updateTexturedRectGeometry(n<span class="operator">-</span><span class="operator">></span>geometry()<span class="operator">,</span> boundingRect()<span class="operator">,</span> <span class="type"><a href="../qtcore/qrectf.html">QRectF</a></span>(<span class="number">0</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="number">1</span><span class="operator">,</span> <span class="number">1</span>));
<span class="keyword">static_cast</span><span class="operator"><</span><span class="type"><a href="qsgsimplematerial.html">QSGSimpleMaterial</a></span><span class="operator"><</span>State<span class="operator">></span><span class="operator">*</span><span class="operator">></span>(n<span class="operator">-</span><span class="operator">></span>material())<span class="operator">-</span><span class="operator">></span>state()<span class="operator">-</span><span class="operator">></span>color <span class="operator">=</span> m_color;
n<span class="operator">-</span><span class="operator">></span>markDirty(<span class="type"><a href="qsgnode.html">QSGNode</a></span><span class="operator">::</span>DirtyGeometry <span class="operator">|</span> <span class="type"><a href="qsgnode.html">QSGNode</a></span><span class="operator">::</span>DirtyMaterial);
<span class="keyword">return</span> n;
}
};
</pre>
<p>Whenever the Item has changed graphically, the <a href="qquickitem.html#updatePaintNode">QQuickItem::updatePaintNode</a>() function is called.</p>
<p><b>Note: </b>The scene graph may be rendered in a different thread than the GUI thread and <a href="qquickitem.html#updatePaintNode">QQuickItem::updatePaintNode</a>() 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 <a href="qquickitem.html">QQuickItem</a> should be contained within this function. The function is called on the rendering thread while the GUI thread is blocked.</p><p>The first time this function is called for an <code>Item</code> instance, the node will be 0, and so 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.</p>
<p>Once we have a <code>ColorNode</code>, we update its geometry and material state. Finally, we notify the scene graph that the node has undergone changes to its geometry and material.</p>
<pre class="cpp">
<span class="type">int</span> main(<span class="type">int</span> argc<span class="operator">,</span> <span class="type">char</span> <span class="operator">*</span><span class="operator">*</span>argv)
{
<span class="type"><a href="../qtgui/qguiapplication.html">QGuiApplication</a></span> app(argc<span class="operator">,</span> argv);
qmlRegisterType<span class="operator"><</span>Item<span class="operator">></span>(<span class="string">"SimpleMaterial"</span><span class="operator">,</span> <span class="number">1</span><span class="operator">,</span> <span class="number">0</span><span class="operator">,</span> <span class="string">"SimpleMaterialItem"</span>);
<span class="type"><a href="qquickview.html">QQuickView</a></span> view;
view<span class="operator">.</span>setResizeMode(<span class="type"><a href="qquickview.html">QQuickView</a></span><span class="operator">::</span>SizeRootObjectToView);
view<span class="operator">.</span>setSource(<span class="type"><a href="../qtcore/qurl.html">QUrl</a></span>(<span class="string">"qrc:///scenegraph/simplematerial/main.qml"</span>));
view<span class="operator">.</span>show();
<span class="keyword">return</span> app<span class="operator">.</span>exec();
}
<span class="preprocessor">#include "simplematerial.moc"</span>
</pre>
<p>The <code>main()</code> function of the application adds the custom QML type using qmlRegisterType() and opens up a <a href="qquickview.html">QQuickView</a> with our QML file.</p>
<pre class="qml">
import QtQuick 2.0
import SimpleMaterial 1.0
<span class="type"><a href="qml-qtquick-rectangle.html">Rectangle</a></span> {
<span class="name">width</span>: <span class="number">320</span>
<span class="name">height</span>: <span class="number">480</span>
<span class="name">color</span>: <span class="string">"black"</span>
</pre>
<p>In the QML file, we import our custom type so we can instantiate it.</p>
<pre class="qml">
<span class="type"><a href="qml-qtquick-column.html">Column</a></span> {
<span class="name">anchors</span>.fill: <span class="name">parent</span>
<span class="type">SimpleMaterialItem</span> {
<span class="name">width</span>: <span class="name">parent</span>.<span class="name">width</span>;
<span class="name">height</span>: <span class="name">parent</span>.<span class="name">height</span> <span class="operator">/</span> <span class="number">3</span>;
<span class="name">color</span>: <span class="string">"steelblue"</span>
}
<span class="type">SimpleMaterialItem</span> {
<span class="name">width</span>: <span class="name">parent</span>.<span class="name">width</span>;
<span class="name">height</span>: <span class="name">parent</span>.<span class="name">height</span> <span class="operator">/</span> <span class="number">3</span>;
<span class="name">color</span>: <span class="string">"darkorchid"</span>
}
<span class="type">SimpleMaterialItem</span> {
<span class="name">width</span>: <span class="name">parent</span>.<span class="name">width</span>;
<span class="name">height</span>: <span class="name">parent</span>.<span class="name">height</span> <span class="operator">/</span> <span class="number">3</span>;
<span class="name">color</span>: <span class="string">"springgreen"</span>
}
}
</pre>
<p>Then we create a column containing three instances of our custom item, each with a different color.</p>
<pre class="qml">
<span class="type"><a href="qml-qtquick-rectangle.html">Rectangle</a></span> {
<span class="name">color</span>: <span class="name">Qt</span>.<span class="name">rgba</span>(<span class="number">0</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">0.8</span>)
<span class="name">radius</span>: <span class="number">10</span>
<span class="name">antialiasing</span>: <span class="number">true</span>
<span class="name">border</span>.width: <span class="number">1</span>
<span class="name">border</span>.color: <span class="string">"black"</span>
<span class="name">anchors</span>.fill: <span class="name">label</span>
<span class="name">anchors</span>.margins: -<span class="number">10</span>
}
<span class="type"><a href="qml-qtquick-text.html">Text</a></span> {
<span class="name">id</span>: <span class="name">label</span>
<span class="name">color</span>: <span class="string">"white"</span>
<span class="name">wrapMode</span>: <span class="name">Text</span>.<span class="name">WordWrap</span>
<span class="name">text</span>: <span class="string">"These three gradient boxes are colorized using a custom material."</span>
<span class="name">anchors</span>.right: <span class="name">parent</span>.<span class="name">right</span>
<span class="name">anchors</span>.left: <span class="name">parent</span>.<span class="name">left</span>
<span class="name">anchors</span>.bottom: <span class="name">parent</span>.<span class="name">bottom</span>
<span class="name">anchors</span>.margins: <span class="number">20</span>
}
}
</pre>
<p>And finally we overlay a short descriptive text.</p>
<p>Files:</p>
<ul>
<li><a href="qtquick-scenegraph-simplematerial-main-qml.html">scenegraph/simplematerial/main.qml</a></li>
<li><a href="qtquick-scenegraph-simplematerial-simplematerial-cpp.html">scenegraph/simplematerial/simplematerial.cpp</a></li>
<li><a href="qtquick-scenegraph-simplematerial-simplematerial-pro.html">scenegraph/simplematerial/simplematerial.pro</a></li>
<li><a href="qtquick-scenegraph-simplematerial-simplematerial-qrc.html">scenegraph/simplematerial/simplematerial.qrc</a></li>
</ul>
</div>
<!-- @@@scenegraph/simplematerial -->
</div>
</div>
</div>
</div>
</div>
<div class="footer">
<p>
<acronym title="Copyright">©</acronym> 2017 The Qt Company Ltd.
Documentation contributions included herein are the copyrights of
their respective owners.<br> The documentation provided herein is licensed under the terms of the <a href="http://www.gnu.org/licenses/fdl.html">GNU Free Documentation License version 1.3</a> as published by the Free Software Foundation.<br> Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property
of their respective owners. </p>
</div>
</body>
</html>
|