Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qquickshadereffectmesh.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6#include <QtQuick/qsggeometry.h>
10#include <QtQuick/private/qsgbasicinternalimagenode_p.h>
11
13
14static const char qt_position_attribute_name[] = "qt_Vertex";
15static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0";
16
18{
20}
21
23{
25}
26
27QQuickShaderEffectMesh::QQuickShaderEffectMesh(QObject *parent)
28 : QObject(parent)
29{
30}
31
32QQuickShaderEffectMesh::QQuickShaderEffectMesh(QObjectPrivate &dd, QObject *parent)
33 : QObject(dd, parent)
34{
35}
36
37/*!
38 \qmltype GridMesh
39 \nativetype QQuickGridMesh
40 \inqmlmodule QtQuick
41 \since 5.0
42 \ingroup qtquick-effects
43 \brief Defines a mesh with vertices arranged in a grid.
44
45 GridMesh defines a rectangular mesh consisting of vertices arranged in an
46 evenly spaced grid. It is used to generate \l{QSGGeometry}{geometry}.
47 The grid resolution is specified with the \l resolution property.
48*/
49
50QQuickGridMesh::QQuickGridMesh(QObject *parent)
51 : QQuickShaderEffectMesh(parent)
52 , m_resolution(1, 1)
53{
54}
55
56bool QQuickGridMesh::validateAttributes(const QList<QByteArray> &attributes, int *posIndex)
57{
58 const int attrCount = attributes.size();
59 int positionIndex = attributes.indexOf(qtPositionAttributeName());
60 int texCoordIndex = attributes.indexOf(qtTexCoordAttributeName());
61
62 switch (attrCount) {
63 case 0:
64 m_log = QLatin1String("Error: No attributes specified.");
65 return false;
66 case 1:
67 if (positionIndex != 0) {
68 m_log = QLatin1String("Error: Missing \'") + QLatin1String(qtPositionAttributeName())
69 + QLatin1String("\' attribute.\n");
70 return false;
71 }
72 break;
73 case 2:
74 if (positionIndex == -1 || texCoordIndex == -1) {
75 m_log.clear();
76 if (positionIndex == -1) {
77 m_log = QLatin1String("Error: Missing \'") + QLatin1String(qtPositionAttributeName())
78 + QLatin1String("\' attribute.\n");
79 }
80 if (texCoordIndex == -1) {
81 m_log += QLatin1String("Error: Missing \'") + QLatin1String(qtTexCoordAttributeName())
82 + QLatin1String("\' attribute.\n");
83 }
84 return false;
85 }
86 break;
87 default:
88 m_log = QLatin1String("Error: Too many attributes specified.");
89 return false;
90 }
91
92 if (posIndex)
93 *posIndex = positionIndex;
94
95 return true;
96}
97
98QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
99 const QRectF &srcRect, const QRectF &dstRect)
100{
101 int vmesh = m_resolution.height();
102 int hmesh = m_resolution.width();
103
104 if (!geometry) {
105 Q_ASSERT(attrCount == 1 || attrCount == 2);
106 geometry = new QSGGeometry(attrCount == 1
107 ? QSGGeometry::defaultAttributes_Point2D()
108 : QSGGeometry::defaultAttributes_TexturedPoint2D(),
109 (vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2),
110 QSGGeometry::UnsignedShortType);
111
112 } else {
113 geometry->allocate((vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2));
114 }
115
116 QSGGeometry::Point2D *vdata = static_cast<QSGGeometry::Point2D *>(geometry->vertexData());
117
118 for (int iy = 0; iy <= vmesh; ++iy) {
119 float fy = iy / float(vmesh);
120 float y = float(dstRect.top()) + fy * float(dstRect.height());
121 float ty = float(srcRect.top()) + fy * float(srcRect.height());
122 for (int ix = 0; ix <= hmesh; ++ix) {
123 float fx = ix / float(hmesh);
124 for (int ia = 0; ia < attrCount; ++ia) {
125 if (ia == posIndex) {
126 vdata->x = float(dstRect.left()) + fx * float(dstRect.width());
127 vdata->y = y;
128 ++vdata;
129 } else {
130 vdata->x = float(srcRect.left()) + fx * float(srcRect.width());
131 vdata->y = ty;
132 ++vdata;
133 }
134 }
135 }
136 }
137
138 quint16 *indices = (quint16 *)geometry->indexDataAsUShort();
139 int i = 0;
140 for (int iy = 0; iy < vmesh; ++iy) {
141 *(indices++) = i + hmesh + 1;
142 for (int ix = 0; ix <= hmesh; ++ix, ++i) {
143 *(indices++) = i + hmesh + 1;
144 *(indices++) = i;
145 }
146 *(indices++) = i - 1;
147 }
148
149 return geometry;
150}
151
152/*!
153 \qmlproperty size QtQuick::GridMesh::resolution
154
155 This property holds the grid resolution. The resolution's width and height
156 specify the number of cells or spacings between vertices horizontally and
157 vertically respectively. The minimum and default is 1x1, which corresponds
158 to four vertices in total, one in each corner.
159 For non-linear vertex transformations, you probably want to set the
160 resolution higher.
161
162 \table
163 \header
164 \li Result
165 \li QML code
166 \li gridmesh.vert
167 \row
168 \li \image declarative-gridmesh.png {Qt logo distorted by GridMesh
169 transformation}
170 \li \qml
171 import QtQuick 2.0
172
173 ShaderEffect {
174 width: 200
175 height: 200
176 mesh: GridMesh {
177 resolution: Qt.size(20, 20)
178 }
179 property variant source: Image {
180 source: "qt-logo.png"
181 sourceSize { width: 200; height: 200 }
182 }
183 vertexShader: "gridmesh.vert"
184 }
185 \endqml
186 \li \badcode
187 #version 440
188 layout(location = 0) in vec4 qt_Vertex;
189 layout(location = 1) in vec2 qt_MultiTexCoord0;
190 layout(location = 0) out vec2 qt_TexCoord0;
191 layout(std140, binding = 0) uniform buf {
192 mat4 qt_Matrix;
193 float qt_Opacity;
194 float width;
195 };
196 void main() {
197 vec4 pos = qt_Vertex;
198 float d = 0.5 * smoothstep(0.0, 1.0, qt_MultiTexCoord0.y);
199 pos.x = width * mix(d, 1.0 - d, qt_MultiTexCoord0.x);
200 gl_Position = qt_Matrix * pos;
201 qt_TexCoord0 = qt_MultiTexCoord0;
202 }
203 \endcode
204 \endtable
205*/
206
207void QQuickGridMesh::setResolution(const QSize &res)
208{
209 if (res == m_resolution)
210 return;
211 if (res.width() < 1 || res.height() < 1) {
212 return;
213 }
214 m_resolution = res;
215 emit resolutionChanged();
216 emit geometryChanged();
217}
218
219QSize QQuickGridMesh::resolution() const
220{
221 return m_resolution;
222}
223
224/*!
225 \qmltype BorderImageMesh
226 \nativetype QQuickBorderImageMesh
227 \inqmlmodule QtQuick
228 \since 5.8
229 \ingroup qtquick-effects
230 \brief Defines a mesh with vertices arranged like those of a BorderImage.
231
232 BorderImageMesh provides BorderImage-like capabilities to a ShaderEffect
233 without the need for a potentially costly ShaderEffectSource.
234
235 The following are functionally equivalent:
236 \qml
237 BorderImage {
238 id: borderImage
239 border {
240 left: 10
241 right: 10
242 top: 10
243 bottom: 10
244 }
245 source: "myImage.png"
246 visible: false
247 }
248 ShaderEffectSource {
249 id: effectSource
250 sourceItem: borderImage
251 visible: false
252 }
253 ShaderEffect {
254 property var source: effectSource
255 ...
256 }
257 \endqml
258
259 \qml
260 Image {
261 id: image
262 source: "myImage.png"
263 visible: false
264 }
265 ShaderEffect {
266 property var source: image
267 mesh: BorderImageMesh {
268 border {
269 left: 10
270 right: 10
271 top: 10
272 bottom: 10
273 }
274 size: image.sourceSize
275 }
276 ...
277 }
278 \endqml
279
280 But the BorderImageMesh version can typically be better optimized.
281*/
282QQuickBorderImageMesh::QQuickBorderImageMesh(QObject *parent)
283 : QQuickShaderEffectMesh(parent), m_border(new QQuickScaleGrid(this)),
284 m_horizontalTileMode(QQuickBorderImageMesh::Stretch),
285 m_verticalTileMode(QQuickBorderImageMesh::Stretch)
286{
287}
288
289bool QQuickBorderImageMesh::validateAttributes(const QList<QByteArray> &attributes, int *posIndex)
290{
291 Q_UNUSED(attributes);
292 Q_UNUSED(posIndex);
293 return true;
294}
295
296QSGGeometry *QQuickBorderImageMesh::updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
297 const QRectF &srcRect, const QRectF &rect)
298{
299 Q_UNUSED(attrCount);
300 Q_UNUSED(posIndex);
301
302 QRectF innerSourceRect;
303 QRectF targetRect;
304 QRectF innerTargetRect;
305 QRectF subSourceRect;
306
307 QQuickBorderImagePrivate::calculateRects(m_border, m_size, rect.size(), m_horizontalTileMode, m_verticalTileMode,
308 1, &targetRect, &innerTargetRect, &innerSourceRect, &subSourceRect);
309
310 QRectF sourceRect = srcRect;
311 QRectF modifiedInnerSourceRect(sourceRect.x() + innerSourceRect.x() * sourceRect.width(),
312 sourceRect.y() + innerSourceRect.y() * sourceRect.height(),
313 innerSourceRect.width() * sourceRect.width(),
314 innerSourceRect.height() * sourceRect.height());
315
316 geometry = QSGBasicInternalImageNode::updateGeometry(targetRect, innerTargetRect, sourceRect,
317 modifiedInnerSourceRect, subSourceRect, geometry);
318
319 return geometry;
320}
321
322/*!
323 \qmlpropertygroup QtQuick::BorderImageMesh::border
324 \qmlproperty int QtQuick::BorderImageMesh::border.left
325 \qmlproperty int QtQuick::BorderImageMesh::border.right
326 \qmlproperty int QtQuick::BorderImageMesh::border.top
327 \qmlproperty int QtQuick::BorderImageMesh::border.bottom
328
329 The 4 border lines (2 horizontal and 2 vertical) break the image into 9 sections,
330 as shown below:
331
332 \image declarative-scalegrid.png {Red rounded rectangle divided into
333 9 numbered regions by dashed border lines}
334
335 Each border line (left, right, top, and bottom) specifies an offset in pixels
336 from the respective edge of the mesh. By default, each border line has
337 a value of 0.
338
339 For example, the following definition sets the bottom line 10 pixels up from
340 the bottom of the mesh:
341
342 \qml
343 BorderImageMesh {
344 border.bottom: 10
345 // ...
346 }
347 \endqml
348*/
349QQuickScaleGrid *QQuickBorderImageMesh::border() const
350{
351 return m_border;
352}
353
354/*!
355 \qmlproperty size QtQuick::BorderImageMesh::size
356
357 The base size of the mesh. This generally corresponds to the \l {Image::}{sourceSize}
358 of the image being used by the ShaderEffect.
359*/
360QSize QQuickBorderImageMesh::size() const
361{
362 return m_size;
363}
364
365void QQuickBorderImageMesh::setSize(const QSize &size)
366{
367 if (size == m_size)
368 return;
369 m_size = size;
370 Q_EMIT sizeChanged();
371 Q_EMIT geometryChanged();
372}
373
374/*!
375 \qmlproperty enumeration QtQuick::BorderImageMesh::horizontalTileMode
376 \qmlproperty enumeration QtQuick::BorderImageMesh::verticalTileMode
377
378 This property describes how to repeat or stretch the middle parts of an image.
379
380 \list
381 \li BorderImage.Stretch - Scales the image to fit to the available area.
382 \li BorderImage.Repeat - Tile the image until there is no more space. May crop the last image.
383 \li BorderImage.Round - Like Repeat, but scales the images down to ensure that the last image is not cropped.
384 \endlist
385
386 The default tile mode for each property is BorderImage.Stretch.
387*/
388
390{
391 return m_horizontalTileMode;
392}
393
395{
396 if (t == m_horizontalTileMode)
397 return;
398 m_horizontalTileMode = t;
399 Q_EMIT horizontalTileModeChanged();
400 Q_EMIT geometryChanged();
401}
402
404{
405 return m_verticalTileMode;
406}
407
409{
410 if (t == m_verticalTileMode)
411 return;
412
413 m_verticalTileMode = t;
414 Q_EMIT verticalTileModeChanged();
415 Q_EMIT geometryChanged();
416}
417
418QT_END_NAMESPACE
419
420#include "moc_qquickshadereffectmesh_p.cpp"
bool validateAttributes(const QList< QByteArray > &attributes, int *posIndex) override
void setSize(const QSize &size)
QQuickScaleGrid * border() const
TileMode horizontalTileMode() const
\qmlproperty enumeration QtQuick::BorderImageMesh::horizontalTileMode \qmlproperty enumeration QtQuic...
QSGGeometry * updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex, const QRectF &srcRect, const QRectF &rect) override
Combined button and popup list for selecting options.
static const char qt_texcoord_attribute_name[]
const char * qtTexCoordAttributeName()
static QT_BEGIN_NAMESPACE const char qt_position_attribute_name[]
const char * qtPositionAttributeName()