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
169 \li \qml
170 import QtQuick 2.0
171
172 ShaderEffect {
173 width: 200
174 height: 200
175 mesh: GridMesh {
176 resolution: Qt.size(20, 20)
177 }
178 property variant source: Image {
179 source: "qt-logo.png"
180 sourceSize { width: 200; height: 200 }
181 }
182 vertexShader: "gridmesh.vert"
183 }
184 \endqml
185 \li \badcode
186 #version 440
187 layout(location = 0) in vec4 qt_Vertex;
188 layout(location = 1) in vec2 qt_MultiTexCoord0;
189 layout(location = 0) out vec2 qt_TexCoord0;
190 layout(std140, binding = 0) uniform buf {
191 mat4 qt_Matrix;
192 float qt_Opacity;
193 float width;
194 };
195 void main() {
196 vec4 pos = qt_Vertex;
197 float d = 0.5 * smoothstep(0.0, 1.0, qt_MultiTexCoord0.y);
198 pos.x = width * mix(d, 1.0 - d, qt_MultiTexCoord0.x);
199 gl_Position = qt_Matrix * pos;
200 qt_TexCoord0 = qt_MultiTexCoord0;
201 }
202 \endcode
203 \endtable
204*/
205
206void QQuickGridMesh::setResolution(const QSize &res)
207{
208 if (res == m_resolution)
209 return;
210 if (res.width() < 1 || res.height() < 1) {
211 return;
212 }
213 m_resolution = res;
214 emit resolutionChanged();
215 emit geometryChanged();
216}
217
218QSize QQuickGridMesh::resolution() const
219{
220 return m_resolution;
221}
222
223/*!
224 \qmltype BorderImageMesh
225 \nativetype QQuickBorderImageMesh
226 \inqmlmodule QtQuick
227 \since 5.8
228 \ingroup qtquick-effects
229 \brief Defines a mesh with vertices arranged like those of a BorderImage.
230
231 BorderImageMesh provides BorderImage-like capabilities to a ShaderEffect
232 without the need for a potentially costly ShaderEffectSource.
233
234 The following are functionally equivalent:
235 \qml
236 BorderImage {
237 id: borderImage
238 border {
239 left: 10
240 right: 10
241 top: 10
242 bottom: 10
243 }
244 source: "myImage.png"
245 visible: false
246 }
247 ShaderEffectSource {
248 id: effectSource
249 sourceItem: borderImage
250 visible: false
251 }
252 ShaderEffect {
253 property var source: effectSource
254 ...
255 }
256 \endqml
257
258 \qml
259 Image {
260 id: image
261 source: "myImage.png"
262 visible: false
263 }
264 ShaderEffect {
265 property var source: image
266 mesh: BorderImageMesh {
267 border {
268 left: 10
269 right: 10
270 top: 10
271 bottom: 10
272 }
273 size: image.sourceSize
274 }
275 ...
276 }
277 \endqml
278
279 But the BorderImageMesh version can typically be better optimized.
280*/
281QQuickBorderImageMesh::QQuickBorderImageMesh(QObject *parent)
282 : QQuickShaderEffectMesh(parent), m_border(new QQuickScaleGrid(this)),
283 m_horizontalTileMode(QQuickBorderImageMesh::Stretch),
284 m_verticalTileMode(QQuickBorderImageMesh::Stretch)
285{
286}
287
288bool QQuickBorderImageMesh::validateAttributes(const QList<QByteArray> &attributes, int *posIndex)
289{
290 Q_UNUSED(attributes);
291 Q_UNUSED(posIndex);
292 return true;
293}
294
295QSGGeometry *QQuickBorderImageMesh::updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
296 const QRectF &srcRect, const QRectF &rect)
297{
298 Q_UNUSED(attrCount);
299 Q_UNUSED(posIndex);
300
301 QRectF innerSourceRect;
302 QRectF targetRect;
303 QRectF innerTargetRect;
304 QRectF subSourceRect;
305
306 QQuickBorderImagePrivate::calculateRects(m_border, m_size, rect.size(), m_horizontalTileMode, m_verticalTileMode,
307 1, &targetRect, &innerTargetRect, &innerSourceRect, &subSourceRect);
308
309 QRectF sourceRect = srcRect;
310 QRectF modifiedInnerSourceRect(sourceRect.x() + innerSourceRect.x() * sourceRect.width(),
311 sourceRect.y() + innerSourceRect.y() * sourceRect.height(),
312 innerSourceRect.width() * sourceRect.width(),
313 innerSourceRect.height() * sourceRect.height());
314
315 geometry = QSGBasicInternalImageNode::updateGeometry(targetRect, innerTargetRect, sourceRect,
316 modifiedInnerSourceRect, subSourceRect, geometry);
317
318 return geometry;
319}
320
321/*!
322 \qmlpropertygroup QtQuick::BorderImageMesh::border
323 \qmlproperty int QtQuick::BorderImageMesh::border.left
324 \qmlproperty int QtQuick::BorderImageMesh::border.right
325 \qmlproperty int QtQuick::BorderImageMesh::border.top
326 \qmlproperty int QtQuick::BorderImageMesh::border.bottom
327
328 The 4 border lines (2 horizontal and 2 vertical) break the image into 9 sections,
329 as shown below:
330
331 \image declarative-scalegrid.png
332
333 Each border line (left, right, top, and bottom) specifies an offset in pixels
334 from the respective edge of the mesh. By default, each border line has
335 a value of 0.
336
337 For example, the following definition sets the bottom line 10 pixels up from
338 the bottom of the mesh:
339
340 \qml
341 BorderImageMesh {
342 border.bottom: 10
343 // ...
344 }
345 \endqml
346*/
347QQuickScaleGrid *QQuickBorderImageMesh::border() const
348{
349 return m_border;
350}
351
352/*!
353 \qmlproperty size QtQuick::BorderImageMesh::size
354
355 The base size of the mesh. This generally corresponds to the \l {Image::}{sourceSize}
356 of the image being used by the ShaderEffect.
357*/
358QSize QQuickBorderImageMesh::size() const
359{
360 return m_size;
361}
362
363void QQuickBorderImageMesh::setSize(const QSize &size)
364{
365 if (size == m_size)
366 return;
367 m_size = size;
368 Q_EMIT sizeChanged();
369 Q_EMIT geometryChanged();
370}
371
372/*!
373 \qmlproperty enumeration QtQuick::BorderImageMesh::horizontalTileMode
374 \qmlproperty enumeration QtQuick::BorderImageMesh::verticalTileMode
375
376 This property describes how to repeat or stretch the middle parts of an image.
377
378 \list
379 \li BorderImage.Stretch - Scales the image to fit to the available area.
380 \li BorderImage.Repeat - Tile the image until there is no more space. May crop the last image.
381 \li BorderImage.Round - Like Repeat, but scales the images down to ensure that the last image is not cropped.
382 \endlist
383
384 The default tile mode for each property is BorderImage.Stretch.
385*/
386
388{
389 return m_horizontalTileMode;
390}
391
393{
394 if (t == m_horizontalTileMode)
395 return;
396 m_horizontalTileMode = t;
397 Q_EMIT horizontalTileModeChanged();
398 Q_EMIT geometryChanged();
399}
400
402{
403 return m_verticalTileMode;
404}
405
407{
408 if (t == m_verticalTileMode)
409 return;
410
411 m_verticalTileMode = t;
412 Q_EMIT verticalTileModeChanged();
413 Q_EMIT geometryChanged();
414}
415
416QT_END_NAMESPACE
417
418#include "moc_qquickshadereffectmesh_p.cpp"
void setSize(const QSize &size)
QQuickScaleGrid * border() const
bool validateAttributes(const QVector< QByteArray > &attributes, int *posIndex) override
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
static const char qt_texcoord_attribute_name[]
const char * qtTexCoordAttributeName()
static QT_BEGIN_NAMESPACE const char qt_position_attribute_name[]
const char * qtPositionAttributeName()