aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/items/qquickshadereffectmesh.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/items/qquickshadereffectmesh.cpp')
-rw-r--r--src/quick/items/qquickshadereffectmesh.cpp287
1 files changed, 253 insertions, 34 deletions
diff --git a/src/quick/items/qquickshadereffectmesh.cpp b/src/quick/items/qquickshadereffectmesh.cpp
index 0811025654..8616bf8022 100644
--- a/src/quick/items/qquickshadereffectmesh.cpp
+++ b/src/quick/items/qquickshadereffectmesh.cpp
@@ -40,9 +40,25 @@
#include "qquickshadereffectmesh_p.h"
#include <QtQuick/qsggeometry.h>
#include "qquickshadereffect_p.h"
+#include "qquickscalegrid_p_p.h"
+#include "qquickborderimage_p_p.h"
+#include <QtQuick/private/qsgbasicinternalimagenode_p.h>
QT_BEGIN_NAMESPACE
+static const char qt_position_attribute_name[] = "qt_Vertex";
+static const char qt_texcoord_attribute_name[] = "qt_MultiTexCoord0";
+
+const char *qtPositionAttributeName()
+{
+ return qt_position_attribute_name;
+}
+
+const char *qtTexCoordAttributeName()
+{
+ return qt_texcoord_attribute_name;
+}
+
QQuickShaderEffectMesh::QQuickShaderEffectMesh(QObject *parent)
: QObject(parent)
{
@@ -67,54 +83,64 @@ QQuickGridMesh::QQuickGridMesh(QObject *parent)
{
}
-QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector<QByteArray> &attributes, const QRectF &srcRect, const QRectF &dstRect)
+bool QQuickGridMesh::validateAttributes(const QVector<QByteArray> &attributes, int *posIndex)
{
- int vmesh = m_resolution.height();
- int hmesh = m_resolution.width();
- int attrCount = attributes.count();
-
+ const int attrCount = attributes.count();
int positionIndex = attributes.indexOf(qtPositionAttributeName());
int texCoordIndex = attributes.indexOf(qtTexCoordAttributeName());
- if (!geometry) {
- switch (attrCount) {
- case 0:
- m_log = QLatin1String("Error: No attributes specified.");
- return 0;
- case 1:
- if (positionIndex != 0) {
+ switch (attrCount) {
+ case 0:
+ m_log = QLatin1String("Error: No attributes specified.");
+ return false;
+ case 1:
+ if (positionIndex != 0) {
+ m_log = QLatin1String("Error: Missing \'");
+ m_log += QLatin1String(qtPositionAttributeName());
+ m_log += QLatin1String("\' attribute.\n");
+ return false;
+ }
+ break;
+ case 2:
+ if (positionIndex == -1 || texCoordIndex == -1) {
+ m_log.clear();
+ if (positionIndex == -1) {
m_log = QLatin1String("Error: Missing \'");
m_log += QLatin1String(qtPositionAttributeName());
m_log += QLatin1String("\' attribute.\n");
- return 0;
}
- break;
- case 2:
- if (positionIndex == -1 || texCoordIndex == -1) {
- m_log.clear();
- if (positionIndex == -1) {
- m_log = QLatin1String("Error: Missing \'");
- m_log += QLatin1String(qtPositionAttributeName());
- m_log += QLatin1String("\' attribute.\n");
- }
- if (texCoordIndex == -1) {
- m_log += QLatin1String("Error: Missing \'");
- m_log += QLatin1String(qtTexCoordAttributeName());
- m_log += QLatin1String("\' attribute.\n");
- }
- return 0;
+ if (texCoordIndex == -1) {
+ m_log += QLatin1String("Error: Missing \'");
+ m_log += QLatin1String(qtTexCoordAttributeName());
+ m_log += QLatin1String("\' attribute.\n");
}
- break;
- default:
- m_log = QLatin1String("Error: Too many attributes specified.");
- return 0;
+ return false;
}
+ break;
+ default:
+ m_log = QLatin1String("Error: Too many attributes specified.");
+ return false;
+ }
+
+ if (posIndex)
+ *posIndex = positionIndex;
+
+ return true;
+}
+QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
+ const QRectF &srcRect, const QRectF &dstRect)
+{
+ int vmesh = m_resolution.height();
+ int hmesh = m_resolution.width();
+
+ if (!geometry) {
+ Q_ASSERT(attrCount == 1 || attrCount == 2);
geometry = new QSGGeometry(attrCount == 1
? QSGGeometry::defaultAttributes_Point2D()
: QSGGeometry::defaultAttributes_TexturedPoint2D(),
(vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2),
- GL_UNSIGNED_SHORT);
+ QSGGeometry::TypeUnsignedShort);
} else {
geometry->allocate((vmesh + 1) * (hmesh + 1), vmesh * 2 * (hmesh + 2));
@@ -129,7 +155,7 @@ QSGGeometry *QQuickGridMesh::updateGeometry(QSGGeometry *geometry, const QVector
for (int ix = 0; ix <= hmesh; ++ix) {
float fx = ix / float(hmesh);
for (int ia = 0; ia < attrCount; ++ia) {
- if (ia == positionIndex) {
+ if (ia == posIndex) {
vdata->x = float(dstRect.left()) + fx * float(dstRect.width());
vdata->y = y;
++vdata;
@@ -217,4 +243,197 @@ QSize QQuickGridMesh::resolution() const
return m_resolution;
}
+/*!
+ \qmltype BorderImageMesh
+ \instantiates QQuickBorderImageMesh
+ \inqmlmodule QtQuick
+ \since 5.8
+ \ingroup qtquick-effects
+ \brief Defines a mesh with vertices arranged like those of a BorderImage.
+
+ BorderImageMesh provides BorderImage-like capabilities to a ShaderEffect
+ without the need for a potentially costly ShaderEffectSource.
+
+ The following are functionally equivalent:
+ \qml
+ BorderImage {
+ id: borderImage
+ border {
+ left: 10
+ right: 10
+ top: 10
+ bottom: 10
+ }
+ source: "myImage.png"
+ visible: false
+ }
+ ShaderEffectSource {
+ id: effectSource
+ sourceItem: borderImage
+ visible: false
+ }
+ ShaderEffect {
+ property var source: effectSource
+ ...
+ }
+ \endqml
+
+ \qml
+ Image {
+ id: image
+ source: "myImage.png"
+ visible: false
+ }
+ ShaderEffect {
+ property var source: image
+ mesh: BorderImageMesh {
+ border {
+ left: 10
+ right: 10
+ top: 10
+ bottom: 10
+ }
+ size: image.sourceSize
+ }
+ ...
+ }
+ \endqml
+
+ But the BorderImageMesh version can typically be better optimized.
+*/
+QQuickBorderImageMesh::QQuickBorderImageMesh(QObject *parent)
+ : QQuickShaderEffectMesh(parent), m_border(new QQuickScaleGrid(this)),
+ m_horizontalTileMode(QQuickBorderImageMesh::Stretch),
+ m_verticalTileMode(QQuickBorderImageMesh::Stretch)
+{
+}
+
+bool QQuickBorderImageMesh::validateAttributes(const QVector<QByteArray> &attributes, int *posIndex)
+{
+ Q_UNUSED(attributes);
+ Q_UNUSED(posIndex);
+ return true;
+}
+
+QSGGeometry *QQuickBorderImageMesh::updateGeometry(QSGGeometry *geometry, int attrCount, int posIndex,
+ const QRectF &srcRect, const QRectF &rect)
+{
+ Q_UNUSED(attrCount);
+ Q_UNUSED(posIndex);
+
+ QRectF innerSourceRect;
+ QRectF targetRect;
+ QRectF innerTargetRect;
+ QRectF subSourceRect;
+
+ QQuickBorderImagePrivate::calculateRects(m_border, m_size, rect.size(), m_horizontalTileMode, m_verticalTileMode,
+ 1, &targetRect, &innerTargetRect, &innerSourceRect, &subSourceRect);
+
+ QRectF sourceRect = srcRect;
+ QRectF modifiedInnerSourceRect(sourceRect.x() + innerSourceRect.x() * sourceRect.width(),
+ sourceRect.y() + innerSourceRect.y() * sourceRect.height(),
+ innerSourceRect.width() * sourceRect.width(),
+ innerSourceRect.height() * sourceRect.height());
+
+ geometry = QSGBasicInternalImageNode::updateGeometry(targetRect, innerTargetRect, sourceRect,
+ modifiedInnerSourceRect, subSourceRect, geometry);
+
+ return geometry;
+}
+
+/*!
+ \qmlpropertygroup QtQuick::BorderImageMesh::border
+ \qmlproperty int QtQuick::BorderImageMesh::border.left
+ \qmlproperty int QtQuick::BorderImageMesh::border.right
+ \qmlproperty int QtQuick::BorderImageMesh::border.top
+ \qmlproperty int QtQuick::BorderImageMesh::border.bottom
+
+ The 4 border lines (2 horizontal and 2 vertical) break the image into 9 sections,
+ as shown below:
+
+ \image declarative-scalegrid.png
+
+ Each border line (left, right, top, and bottom) specifies an offset in pixels
+ from the respective edge of the mesh. By default, each border line has
+ a value of 0.
+
+ For example, the following definition sets the bottom line 10 pixels up from
+ the bottom of the mesh:
+
+ \qml
+ BorderImageMesh {
+ border.bottom: 10
+ // ...
+ }
+ \endqml
+*/
+QQuickScaleGrid *QQuickBorderImageMesh::border()
+{
+ return m_border;
+}
+
+/*!
+ \qmlproperty size QtQuick::BorderImageMesh::size
+
+ The base size of the mesh. This generally corresponds to the \l {Image::}{sourceSize}
+ of the image being used by the ShaderEffect.
+*/
+QSize QQuickBorderImageMesh::size() const
+{
+ return m_size;
+}
+
+void QQuickBorderImageMesh::setSize(const QSize &size)
+{
+ if (size == m_size)
+ return;
+ m_size = size;
+ Q_EMIT sizeChanged();
+ Q_EMIT geometryChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick::BorderImageMesh::horizontalTileMode
+ \qmlproperty enumeration QtQuick::BorderImageMesh::verticalTileMode
+
+ This property describes how to repeat or stretch the middle parts of an image.
+
+ \list
+ \li BorderImage.Stretch - Scales the image to fit to the available area.
+ \li BorderImage.Repeat - Tile the image until there is no more space. May crop the last image.
+ \li BorderImage.Round - Like Repeat, but scales the images down to ensure that the last image is not cropped.
+ \endlist
+
+ The default tile mode for each property is BorderImage.Stretch.
+*/
+
+QQuickBorderImageMesh::TileMode QQuickBorderImageMesh::horizontalTileMode() const
+{
+ return m_horizontalTileMode;
+}
+
+void QQuickBorderImageMesh::setHorizontalTileMode(TileMode t)
+{
+ if (t == m_horizontalTileMode)
+ return;
+ m_horizontalTileMode = t;
+ Q_EMIT horizontalTileModeChanged();
+ Q_EMIT geometryChanged();
+}
+
+QQuickBorderImageMesh::TileMode QQuickBorderImageMesh::verticalTileMode() const
+{
+ return m_verticalTileMode;
+}
+
+void QQuickBorderImageMesh::setVerticalTileMode(TileMode t)
+{
+ if (t == m_verticalTileMode)
+ return;
+
+ m_verticalTileMode = t;
+ Q_EMIT verticalTileModeChanged();
+ Q_EMIT geometryChanged();
+}
+
QT_END_NAMESPACE