diff options
Diffstat (limited to 'src/quick/items/qquickshadereffectmesh.cpp')
-rw-r--r-- | src/quick/items/qquickshadereffectmesh.cpp | 287 |
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 |