diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2016-12-03 21:30:12 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2016-12-19 17:03:46 +0000 |
commit | c9023c28764e70cd1c6f9cfc3506e6185299548e (patch) | |
tree | 1578cf3ea1f97b024f036b923cb1e02fee0b92cc /src/quick | |
parent | 25277124d8b7581a9390702ad3d4bcd4be8dedd7 (diff) | |
download | qtdeclarative-c9023c28764e70cd1c6f9cfc3506e6185299548e.tar.gz |
Add QQuickPathItem and its backend infra
The generic backend uses the triangulator from QtGui, but is in
fact OpenGL-only for now due to materials.
The NVPR backend uses GL_NV_path_rendering on NVIDIA hardware with
OpenGL 4.3+ or OpenGL ES 3.1+.
The software backend simply uses QPainter.
With the generic backend each PathItem is backed by a non-visual root node
and 0, 1 or 2 child geometry nodes, depending on the presence of visible
stroking and filling. The potentially expensive triangulation happens on
updatePolish(), on the gui thread. This is proven to provide much smoother
results when compared to doing the geometry generation on the render thread
in updatePaintNode(), in particular on power-limited embedded devices.
The NVPR backend uses a QSGRenderNode in DepthAware mode so that the batch
renderer can continue to rely on the depth buffer and use opaque batches.
Due to not relying on slow CPU-side triangulation, this backend uses 5-10
times less CPU, even when properties of the path or its elements are
animated.
The path itself is specified with the PathView's Path, PathLine, PathArc,
PathQuad, etc. types. This allows for consistency with PathView and the
2D Canvas and avoids a naming mess in the API. However, there won't be a
100% symmetry: backends like NVPR will not rely on QPainterPath but process
the path elements on their own (as QPainterPath is essentially useless with
these APIs), which can lead to differences in the supported path elements.
The supported common set is currently Move, Line, Quad, Cubic, Arc.
The patch introduces PathMove, which is essentially PathLine but maps to
moveTo instead of lineTo. More types may get added later (e.g. NVPR can do
a wide variety of optimized rounded rects, but this requires directly
specifying a GL_ROUNDED_RECTx_NV command, thus neededing a dedicated Path
type on our side too)
For filling with gradients only linear gradients are supported at the
moment.
In addition to the declarative API, a more lightweight, QObject-less
JS-callable API should be considered as well for the future.
Change-Id: I335ad64b425ee279505d60e3e57ac6841e1cbd24
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src/quick')
29 files changed, 4068 insertions, 18 deletions
diff --git a/src/quick/items/items.pri b/src/quick/items/items.pri index 0f8061b5ef..511c6f18d8 100644 --- a/src/quick/items/items.pri +++ b/src/quick/items/items.pri @@ -148,9 +148,20 @@ qtConfig(quick-listview) { qtConfig(quick-pathview) { HEADERS += \ $$PWD/qquickpathview_p.h \ - $$PWD/qquickpathview_p_p.h + $$PWD/qquickpathview_p_p.h \ + $$PWD/qquickpathitem_p.h \ + $$PWD/qquickpathitem_p_p.h \ + $$PWD/qquickpathitemgenericrenderer_p.h \ + $$PWD/qquickpathitemsoftwarerenderer_p.h SOURCES += \ - $$PWD/qquickpathview.cpp + $$PWD/qquickpathview.cpp \ + $$PWD/qquickpathitem.cpp \ + $$PWD/qquickpathitemgenericrenderer.cpp \ + $$PWD/qquickpathitemsoftwarerenderer.cpp + qtConfig(opengl) { + HEADERS += $$PWD/qquickpathitemnvprrenderer_p.h + SOURCES += $$PWD/qquickpathitemnvprrenderer.cpp + } } qtConfig(quick-positioners) { diff --git a/src/quick/items/items.qrc b/src/quick/items/items.qrc index 6aaf757c29..da9bf0c828 100644 --- a/src/quick/items/items.qrc +++ b/src/quick/items/items.qrc @@ -8,5 +8,9 @@ <file>shaders/shadereffect_core.vert</file> <file>shaders/shadereffectfallback_core.frag</file> <file>shaders/shadereffectfallback_core.vert</file> + <file>shaders/lineargradient.vert</file> + <file>shaders/lineargradient.frag</file> + <file>shaders/lineargradient_core.vert</file> + <file>shaders/lineargradient_core.frag</file> </qresource> </RCC> diff --git a/src/quick/items/qquickitemsmodule.cpp b/src/quick/items/qquickitemsmodule.cpp index dbe30fbc83..b0d7f7f8a3 100644 --- a/src/quick/items/qquickitemsmodule.cpp +++ b/src/quick/items/qquickitemsmodule.cpp @@ -70,6 +70,7 @@ #if QT_CONFIG(quick_path) #include <private/qquickpath_p.h> #include <private/qquickpathinterpolator_p.h> +#include "qquickpathitem_p.h" #endif #if QT_CONFIG(quick_positioners) #include "qquickpositioners_p.h" @@ -370,6 +371,14 @@ static void qt_quickitems_defineModule(const char *uri, int major, int minor) #endif qmlRegisterType<QQuickMouseArea, 9>(uri, 2, 9, "MouseArea"); + +#if QT_CONFIG(quick_path) + qmlRegisterType<QQuickPathMove>(uri, 2, 9, "PathMove"); + qmlRegisterType<QQuickPathItem>(uri, 2, 9, "PathItem"); + qmlRegisterType<QQuickPathGradientStop>(uri, 2, 9, "PathGradientStop"); + qmlRegisterUncreatableType<QQuickPathGradient>(uri, 2, 9, "PathGradient", QQuickPathGradient::tr("PathGradient is an abstract base class")); + qmlRegisterType<QQuickPathLinearGradient>(uri, 2, 9, "PathLinearGradient"); +#endif } static void initResources() diff --git a/src/quick/items/qquickpathitem.cpp b/src/quick/items/qquickpathitem.cpp new file mode 100644 index 0000000000..0d2c7a8bbe --- /dev/null +++ b/src/quick/items/qquickpathitem.cpp @@ -0,0 +1,792 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpathitem_p.h" +#include "qquickpathitem_p_p.h" +#include "qquickpathitemgenericrenderer_p.h" +#include "qquickpathitemnvprrenderer_p.h" +#include "qquickpathitemsoftwarerenderer_p.h" +#include <private/qsgtexture_p.h> +#include <QtGui/private/qdrawhelper_p.h> +#include <QOpenGLFunctions> + +QT_BEGIN_NAMESPACE + +QQuickPathItemPrivate::QQuickPathItemPrivate() + : rendererType(QQuickPathItem::UnknownRenderer), + renderer(nullptr), + path(nullptr), + dirty(DirtyAll), + strokeColor(Qt::white), + strokeWidth(1), + fillColor(Qt::white), + fillRule(QQuickPathItem::OddEvenFill), + joinStyle(QQuickPathItem::BevelJoin), + miterLimit(2), + capStyle(QQuickPathItem::SquareCap), + strokeStyle(QQuickPathItem::SolidLine), + dashOffset(0), + fillGradient(nullptr) +{ + dashPattern << 4 << 2; // 4 * strokeWidth dash followed by 2 * strokeWidth space +} + +QQuickPathItemPrivate::~QQuickPathItemPrivate() +{ + delete renderer; +} + +/*! + \qmltype PathItem + \instantiates QQuickPathItem + \inqmlmodule QtQuick + \ingroup qtquick-paths + \ingroup qtquick-views + \inherits Item + \brief Renders a path + + Renders a path either by generating geometry via QPainterPath and manual + triangulation or by using an extension like \c{GL_NV_path_rendering}. + + This approach is different from rendering shapes via QQuickPaintedItem or + the 2D Canvas because the path never gets rasterized in software. Therefore + it is suitable for creating shapes spreading over larger areas of the + screen, avoiding the performance penalty for texture uploads or framebuffer + blits. + + Nonetheless it is important to be aware of performance implications, in + particular when the application is running on the generic PathItem + implementation due to not having support for accelerated path rendering. + The geometry generation happens entirely on the CPU in this case, and this + is potentially expensive. Changing the set of path elements, changing the + properties of these elements, or changing certain properties of the + PathItem itself all lead to retriangulation on every change. Therefore, + applying animation to such properties can heavily affect performance on + less powerful systems. If animating properties other than stroke and fill + colors is a must, it is recommended to target systems providing + \c{GL_NV_path_rendering} where the cost of path property changes is much + smaller. + + \note The types for specifying path elements are shared between PathView + and PathItem. However, not all PathItem implementations support all path + element types, while some may not make sense for PathView. PathItem's + currently supported subset is: PathMove, PathLine, PathQuad, PathCubic, + PathArc. + + \sa Path, PathMove, PathLine, PathQuad, PathCubic, PathArc +*/ + +QQuickPathItem::QQuickPathItem(QQuickItem *parent) + : QQuickItem(*(new QQuickPathItemPrivate), parent) +{ + setFlag(ItemHasContents); +} + +QQuickPathItem::~QQuickPathItem() +{ +} + +QQuickPathItem::RendererType QQuickPathItem::rendererType() const +{ + Q_D(const QQuickPathItem); + return d->rendererType; +} + +/*! + \qmlproperty Path QtQuick::PathItem::path + This property holds the path to be rendered. + For more information see the \l Path documentation. +*/ +QQuickPath *QQuickPathItem::path() const +{ + Q_D(const QQuickPathItem); + return d->path; +} + +void QQuickPathItem::setPath(QQuickPath *path) +{ + Q_D(QQuickPathItem); + if (d->path == path) + return; + + if (d->path) + qmlobject_disconnect(d->path, QQuickPath, SIGNAL(changed()), + this, QQuickPathItem, SLOT(_q_pathChanged())); + d->path = path; + qmlobject_connect(d->path, QQuickPath, SIGNAL(changed()), + this, QQuickPathItem, SLOT(_q_pathChanged())); + + d->dirty |= QQuickPathItemPrivate::DirtyPath; + emit pathChanged(); + polish(); +} + +void QQuickPathItemPrivate::_q_pathChanged() +{ + Q_Q(QQuickPathItem); + dirty |= DirtyPath; + q->polish(); +} + +QColor QQuickPathItem::strokeColor() const +{ + Q_D(const QQuickPathItem); + return d->strokeColor; +} + +void QQuickPathItem::setStrokeColor(const QColor &color) +{ + Q_D(QQuickPathItem); + if (d->strokeColor != color) { + d->strokeColor = color; + d->dirty |= QQuickPathItemPrivate::DirtyStrokeColor; + emit strokeColorChanged(); + polish(); + } +} + +qreal QQuickPathItem::strokeWidth() const +{ + Q_D(const QQuickPathItem); + return d->strokeWidth; +} + +void QQuickPathItem::setStrokeWidth(qreal w) +{ + Q_D(QQuickPathItem); + if (d->strokeWidth != w) { + d->strokeWidth = w; + d->dirty |= QQuickPathItemPrivate::DirtyStrokeWidth; + emit strokeWidthChanged(); + polish(); + } +} + +QColor QQuickPathItem::fillColor() const +{ + Q_D(const QQuickPathItem); + return d->fillColor; +} + +void QQuickPathItem::setFillColor(const QColor &color) +{ + Q_D(QQuickPathItem); + if (d->fillColor != color) { + d->fillColor = color; + d->dirty |= QQuickPathItemPrivate::DirtyFillColor; + emit fillColorChanged(); + polish(); + } +} + +QQuickPathItem::FillRule QQuickPathItem::fillRule() const +{ + Q_D(const QQuickPathItem); + return d->fillRule; +} + +void QQuickPathItem::setFillRule(FillRule fillRule) +{ + Q_D(QQuickPathItem); + if (d->fillRule != fillRule) { + d->fillRule = fillRule; + d->dirty |= QQuickPathItemPrivate::DirtyFillRule; + emit fillRuleChanged(); + polish(); + } +} + +QQuickPathItem::JoinStyle QQuickPathItem::joinStyle() const +{ + Q_D(const QQuickPathItem); + return d->joinStyle; +} + +void QQuickPathItem::setJoinStyle(JoinStyle style) +{ + Q_D(QQuickPathItem); + if (d->joinStyle != style) { + d->joinStyle = style; + d->dirty |= QQuickPathItemPrivate::DirtyStyle; + emit joinStyleChanged(); + polish(); + } +} + +int QQuickPathItem::miterLimit() const +{ + Q_D(const QQuickPathItem); + return d->miterLimit; +} + +void QQuickPathItem::setMiterLimit(int limit) +{ + Q_D(QQuickPathItem); + if (d->miterLimit != limit) { + d->miterLimit = limit; + d->dirty |= QQuickPathItemPrivate::DirtyStyle; + emit miterLimitChanged(); + polish(); + } +} + +QQuickPathItem::CapStyle QQuickPathItem::capStyle() const +{ + Q_D(const QQuickPathItem); + return d->capStyle; +} + +void QQuickPathItem::setCapStyle(CapStyle style) +{ + Q_D(QQuickPathItem); + if (d->capStyle != style) { + d->capStyle = style; + d->dirty |= QQuickPathItemPrivate::DirtyStyle; + emit capStyleChanged(); + polish(); + } +} + +QQuickPathItem::StrokeStyle QQuickPathItem::strokeStyle() const +{ + Q_D(const QQuickPathItem); + return d->strokeStyle; +} + +void QQuickPathItem::setStrokeStyle(StrokeStyle style) +{ + Q_D(QQuickPathItem); + if (d->strokeStyle != style) { + d->strokeStyle = style; + d->dirty |= QQuickPathItemPrivate::DirtyDash; + emit strokeStyleChanged(); + polish(); + } +} + +qreal QQuickPathItem::dashOffset() const +{ + Q_D(const QQuickPathItem); + return d->dashOffset; +} + +void QQuickPathItem::setDashOffset(qreal offset) +{ + Q_D(QQuickPathItem); + if (d->dashOffset != offset) { + d->dashOffset = offset; + d->dirty |= QQuickPathItemPrivate::DirtyDash; + emit dashOffsetChanged(); + polish(); + } +} + +QVector<qreal> QQuickPathItem::dashPattern() const +{ + Q_D(const QQuickPathItem); + return d->dashPattern; +} + +void QQuickPathItem::setDashPattern(const QVector<qreal> &array) +{ + Q_D(QQuickPathItem); + if (d->dashPattern != array) { + d->dashPattern = array; + d->dirty |= QQuickPathItemPrivate::DirtyDash; + emit dashPatternChanged(); + polish(); + } +} + +QQuickPathGradient *QQuickPathItem::fillGradient() const +{ + Q_D(const QQuickPathItem); + return d->fillGradient; +} + +void QQuickPathItem::setFillGradient(QQuickPathGradient *gradient) +{ + Q_D(QQuickPathItem); + if (d->fillGradient != gradient) { + if (d->fillGradient) + qmlobject_disconnect(d->fillGradient, QQuickPathGradient, SIGNAL(updated()), + this, QQuickPathItem, SLOT(_q_fillGradientChanged())); + d->fillGradient = gradient; + if (d->fillGradient) + qmlobject_connect(d->fillGradient, QQuickPathGradient, SIGNAL(updated()), + this, QQuickPathItem, SLOT(_q_fillGradientChanged())); + d->dirty |= QQuickPathItemPrivate::DirtyFillGradient; + polish(); + } +} + +void QQuickPathItemPrivate::_q_fillGradientChanged() +{ + Q_Q(QQuickPathItem); + dirty |= DirtyFillGradient; + q->polish(); +} + +void QQuickPathItem::resetFillGradient() +{ + setFillGradient(nullptr); +} + +void QQuickPathItem::updatePolish() +{ + Q_D(QQuickPathItem); + + if (!d->dirty) + return; + + if (!d->renderer) { + d->createRenderer(); + if (!d->renderer) + return; + emit rendererChanged(); + } + + // endSync() is where expensive calculations may happen, depending on the + // backend. Therefore do this only when the item is visible. + if (isVisible()) + d->sync(); + + update(); +} + +void QQuickPathItem::itemChange(ItemChange change, const ItemChangeData &data) +{ + // sync may have been deferred; do it now if the item became visible + if (change == ItemVisibleHasChanged && data.boolValue) + polish(); + + QQuickItem::itemChange(change, data); +} + +QSGNode *QQuickPathItem::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) +{ + // Called on the render thread, with the gui thread blocked. We can now + // safely access gui thread data. + + Q_D(QQuickPathItem); + if (d->renderer) { + if (!node) + node = d->createRenderNode(); + d->renderer->updatePathRenderNode(); + } + return node; +} + +// the renderer object lives on the gui thread +void QQuickPathItemPrivate::createRenderer() +{ + Q_Q(QQuickPathItem); + QSGRendererInterface *ri = q->window()->rendererInterface(); + if (!ri) + return; + + switch (ri->graphicsApi()) { +#ifndef QT_NO_OPENGL + case QSGRendererInterface::OpenGL: + if (QQuickPathItemNvprRenderNode::isSupported()) { + rendererType = QQuickPathItem::NvprRenderer; + renderer = new QQuickPathItemNvprRenderer; + } else { + rendererType = QQuickPathItem::GeometryRenderer; + renderer = new QQuickPathItemGenericRenderer(q); + } + break; +#endif + case QSGRendererInterface::Software: + rendererType = QQuickPathItem::SoftwareRenderer; + renderer = new QQuickPathItemSoftwareRenderer; + break; + default: + qWarning("No path backend for this graphics API yet"); + break; + } +} + +// the node lives on the render thread +QSGNode *QQuickPathItemPrivate::createRenderNode() +{ + Q_Q(QQuickPathItem); + QSGNode *node = nullptr; + if (!q->window()) + return node; + QSGRendererInterface *ri = q->window()->rendererInterface(); + if (!ri) + return node; + + const bool hasFill = fillColor != Qt::transparent; + const bool hasStroke = !qFuzzyIsNull(strokeWidth) && strokeColor != Qt::transparent; + + switch (ri->graphicsApi()) { +#ifndef QT_NO_OPENGL + case QSGRendererInterface::OpenGL: + if (QQuickPathItemNvprRenderNode::isSupported()) { + node = new QQuickPathItemNvprRenderNode(q); + static_cast<QQuickPathItemNvprRenderer *>(renderer)->setNode( + static_cast<QQuickPathItemNvprRenderNode *>(node)); + } else { + node = new QQuickPathItemGenericRootRenderNode(q->window(), hasFill, hasStroke); + static_cast<QQuickPathItemGenericRenderer *>(renderer)->setRootNode( + static_cast<QQuickPathItemGenericRootRenderNode *>(node)); + } + break; +#endif + case QSGRendererInterface::Software: + node = new QQuickPathItemSoftwareRenderNode(q); + static_cast<QQuickPathItemSoftwareRenderer *>(renderer)->setNode( + static_cast<QQuickPathItemSoftwareRenderNode *>(node)); + break; + default: + qWarning("No path backend for this graphics API yet"); + break; + } + + return node; +} + +void QQuickPathItemPrivate::sync() +{ + renderer->beginSync(); + + if (dirty & QQuickPathItemPrivate::DirtyPath) + renderer->setPath(path); + if (dirty & DirtyStrokeColor) + renderer->setStrokeColor(strokeColor); + if (dirty & DirtyStrokeWidth) + renderer->setStrokeWidth(strokeWidth); + if (dirty & DirtyFillColor) + renderer->setFillColor(fillColor); + if (dirty & DirtyFillRule) + renderer->setFillRule(fillRule); + if (dirty & DirtyStyle) { + renderer->setJoinStyle(joinStyle, miterLimit); + renderer->setCapStyle(capStyle); + } + if (dirty & DirtyDash) + renderer->setStrokeStyle(strokeStyle, dashOffset, dashPattern); + if (dirty & DirtyFillGradient) + renderer->setFillGradient(fillGradient); + + renderer->endSync(); + dirty = 0; +} + +// ***** gradient support ***** + +QQuickPathGradientStop::QQuickPathGradientStop(QObject *parent) + : QObject(parent), + m_position(0), + m_color(Qt::black) +{ +} + +qreal QQuickPathGradientStop::position() const +{ + return m_position; +} + +void QQuickPathGradientStop::setPosition(qreal position) +{ + if (m_position != position) { + m_position = position; + if (QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(parent())) + emit grad->updated(); + } +} + +QColor QQuickPathGradientStop::color() const +{ + return m_color; +} + +void QQuickPathGradientStop::setColor(const QColor &color) +{ + if (m_color != color) { + m_color = color; + if (QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(parent())) + emit grad->updated(); + } +} + +QQuickPathGradient::QQuickPathGradient(QObject *parent) + : QObject(parent), + m_spread(PadSpread) +{ +} + +void QQuickPathGradient::appendStop(QQmlListProperty<QObject> *list, QObject *stop) +{ + QQuickPathGradientStop *sstop = qobject_cast<QQuickPathGradientStop *>(stop); + if (!sstop) { + qWarning("Gradient stop list only supports QQuickPathGradientStop elements"); + return; + } + QQuickPathGradient *grad = qobject_cast<QQuickPathGradient *>(list->object); + Q_ASSERT(grad); + sstop->setParent(grad); + grad->m_stops.append(sstop); +} + +QQmlListProperty<QObject> QQuickPathGradient::stops() +{ + return QQmlListProperty<QObject>(this, nullptr, &QQuickPathGradient::appendStop, nullptr, nullptr, nullptr); +} + +QGradientStops QQuickPathGradient::sortedGradientStops() const +{ + QGradientStops result; + for (int i = 0; i < m_stops.count(); ++i) { + QQuickPathGradientStop *s = static_cast<QQuickPathGradientStop *>(m_stops[i]); + int j = 0; + while (j < result.count() && result[j].first < s->position()) + ++j; + result.insert(j, QGradientStop(s->position(), s->color())); + } + return result; +} + +QQuickPathGradient::SpreadMode QQuickPathGradient::spread() const +{ + return m_spread; +} + +void QQuickPathGradient::setSpread(SpreadMode mode) +{ + if (m_spread != mode) { + m_spread = mode; + emit spreadChanged(); + emit updated(); + } +} + +QQuickPathLinearGradient::QQuickPathLinearGradient(QObject *parent) + : QQuickPathGradient(parent) +{ +} + +qreal QQuickPathLinearGradient::x1() const +{ + return m_start.x(); +} + +void QQuickPathLinearGradient::setX1(qreal v) +{ + if (m_start.x() != v) { + m_start.setX(v); + emit x1Changed(); + emit updated(); + } +} + +qreal QQuickPathLinearGradient::y1() const +{ + return m_start.y(); +} + +void QQuickPathLinearGradient::setY1(qreal v) +{ + if (m_start.y() != v) { + m_start.setY(v); + emit y1Changed(); + emit updated(); + } +} + +qreal QQuickPathLinearGradient::x2() const +{ + return m_end.x(); +} + +void QQuickPathLinearGradient::setX2(qreal v) +{ + if (m_end.x() != v) { + m_end.setX(v); + emit x2Changed(); + emit updated(); + } +} + +qreal QQuickPathLinearGradient::y2() const +{ + return m_end.y(); +} + +void QQuickPathLinearGradient::setY2(qreal v) +{ + if (m_end.y() != v) { + m_end.setY(v); + emit y2Changed(); + emit updated(); + } +} + +#ifndef QT_NO_OPENGL + +// contexts sharing with each other get the same cache instance +class QQuickPathItemGradientCacheWrapper +{ +public: + QQuickPathItemGradientCache *get(QOpenGLContext *context) + { + return m_resource.value<QQuickPathItemGradientCache>(context); + } + +private: + QOpenGLMultiGroupSharedResource m_resource; +}; + +QQuickPathItemGradientCache *QQuickPathItemGradientCache::currentCache() +{ + static QQuickPathItemGradientCacheWrapper qt_path_gradient_caches; + return qt_path_gradient_caches.get(QOpenGLContext::currentContext()); +} + +// let QOpenGLContext manage the lifetime of the cached textures +QQuickPathItemGradientCache::~QQuickPathItemGradientCache() +{ + m_cache.clear(); +} + +void QQuickPathItemGradientCache::invalidateResource() +{ + m_cache.clear(); +} + +void QQuickPathItemGradientCache::freeResource(QOpenGLContext *) +{ + qDeleteAll(m_cache); + m_cache.clear(); +} + +static void generateGradientColorTable(const QQuickPathItemGradientCache::GradientDesc &gradient, + uint *colorTable, int size, float opacity) +{ + int pos = 0; + const QGradientStops &s = gradient.stops; + const bool colorInterpolation = true; + + uint alpha = qRound(opacity * 256); + uint current_color = ARGB_COMBINE_ALPHA(s[0].second.rgba(), alpha); + qreal incr = 1.0 / qreal(size); + qreal fpos = 1.5 * incr; + colorTable[pos++] = ARGB2RGBA(qPremultiply(current_color)); + + while (fpos <= s.first().first) { + colorTable[pos] = colorTable[pos - 1]; + pos++; + fpos += incr; + } + + if (colorInterpolation) + current_color = qPremultiply(current_color); + + const int sLast = s.size() - 1; + for (int i = 0; i < sLast; ++i) { + qreal delta = 1/(s[i+1].first - s[i].first); + uint next_color = ARGB_COMBINE_ALPHA(s[i + 1].second.rgba(), alpha); + if (colorInterpolation) + next_color = qPremultiply(next_color); + + while (fpos < s[i+1].first && pos < size) { + int dist = int(256 * ((fpos - s[i].first) * delta)); + int idist = 256 - dist; + if (colorInterpolation) + colorTable[pos] = ARGB2RGBA(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist)); + else + colorTable[pos] = ARGB2RGBA(qPremultiply(INTERPOLATE_PIXEL_256(current_color, idist, next_color, dist))); + ++pos; + fpos += incr; + } + current_color = next_color; + } + + Q_ASSERT(s.size() > 0); + + uint last_color = ARGB2RGBA(qPremultiply(ARGB_COMBINE_ALPHA(s[sLast].second.rgba(), alpha))); + for ( ; pos < size; ++pos) + colorTable[pos] = last_color; + + colorTable[size-1] = last_color; +} + +QSGTexture *QQuickPathItemGradientCache::get(const GradientDesc &grad) +{ + QSGPlainTexture *tx = m_cache[grad]; + if (!tx) { + QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions(); + GLuint id; + f->glGenTextures(1, &id); + f->glBindTexture(GL_TEXTURE_2D, id); + static const uint W = 1024; // texture size is 1024x1 + uint buf[W]; + generateGradientColorTable(grad, buf, W, 1.0f); + f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, W, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); + tx = new QSGPlainTexture; + tx->setTextureId(id); + switch (grad.spread) { + case QQuickPathGradient::PadSpread: + tx->setHorizontalWrapMode(QSGTexture::ClampToEdge); + tx->setVerticalWrapMode(QSGTexture::ClampToEdge); + break; + case QQuickPathGradient::RepeatSpread: + tx->setHorizontalWrapMode(QSGTexture::Repeat); + tx->setVerticalWrapMode(QSGTexture::Repeat); + break; + case QQuickPathGradient::ReflectSpread: + tx->setHorizontalWrapMode(QSGTexture::MirroredRepeat); + tx->setVerticalWrapMode(QSGTexture::MirroredRepeat); + break; + default: + qWarning("Unknown gradient spread mode %d", grad.spread); + break; + } + m_cache[grad] = tx; + } + return tx; +} + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE + +#include "moc_qquickpathitem_p.cpp" diff --git a/src/quick/items/qquickpathitem_p.h b/src/quick/items/qquickpathitem_p.h new file mode 100644 index 0000000000..39b407cf87 --- /dev/null +++ b/src/quick/items/qquickpathitem_p.h @@ -0,0 +1,281 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEM_P_H +#define QQUICKPATHITEM_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickitem.h" + +#include <private/qtquickglobal_p.h> +#include <private/qquickpath_p.h> +#include <QGradientStops> + +QT_REQUIRE_CONFIG(quick_path); + +QT_BEGIN_NAMESPACE + +class QQuickPathItemPrivate; + +class Q_QUICK_PRIVATE_EXPORT QQuickPathGradientStop : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal position READ position WRITE setPosition) + Q_PROPERTY(QColor color READ color WRITE setColor) + +public: + QQuickPathGradientStop(QObject *parent = nullptr); + + qreal position() const; + void setPosition(qreal position); + + QColor color() const; + void setColor(const QColor &color); + +private: + qreal m_position; + QColor m_color; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickPathGradient : public QObject +{ + Q_OBJECT + Q_PROPERTY(QQmlListProperty<QObject> stops READ stops) + Q_PROPERTY(SpreadMode spread READ spread WRITE setSpread NOTIFY spreadChanged) + Q_CLASSINFO("DefaultProperty", "stops") + +public: + enum SpreadMode { + PadSpread, + RepeatSpread, + ReflectSpread + }; + Q_ENUM(SpreadMode) + + QQuickPathGradient(QObject *parent = nullptr); + + QQmlListProperty<QObject> stops(); + + QGradientStops sortedGradientStops() const; + + SpreadMode spread() const; + void setSpread(SpreadMode mode); + +signals: + void updated(); + void spreadChanged(); + +private: + static void appendStop(QQmlListProperty<QObject> *list, QObject *stop); + + QVector<QObject *> m_stops; + SpreadMode m_spread; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickPathLinearGradient : public QQuickPathGradient +{ + Q_OBJECT + Q_PROPERTY(qreal x1 READ x1 WRITE setX1 NOTIFY x1Changed) + Q_PROPERTY(qreal y1 READ y1 WRITE setY1 NOTIFY y1Changed) + Q_PROPERTY(qreal x2 READ x2 WRITE setX2 NOTIFY x2Changed) + Q_PROPERTY(qreal y2 READ y2 WRITE setY2 NOTIFY y2Changed) + Q_CLASSINFO("DefaultProperty", "stops") + +public: + QQuickPathLinearGradient(QObject *parent = nullptr); + + qreal x1() const; + void setX1(qreal v); + qreal y1() const; + void setY1(qreal v); + qreal x2() const; + void setX2(qreal v); + qreal y2() const; + void setY2(qreal v); + +signals: + void x1Changed(); + void y1Changed(); + void x2Changed(); + void y2Changed(); + +private: + QPointF m_start; + QPointF m_end; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickPathItem : public QQuickItem +{ + Q_OBJECT + + Q_PROPERTY(RendererType renderer READ rendererType NOTIFY rendererChanged) + + Q_PROPERTY(QQuickPath *path READ path WRITE setPath NOTIFY pathChanged) + + Q_PROPERTY(QColor strokeColor READ strokeColor WRITE setStrokeColor NOTIFY strokeColorChanged) + Q_PROPERTY(qreal strokeWidth READ strokeWidth WRITE setStrokeWidth NOTIFY strokeWidthChanged) + Q_PROPERTY(QColor fillColor READ fillColor WRITE setFillColor NOTIFY fillColorChanged) + Q_PROPERTY(FillRule fillRule READ fillRule WRITE setFillRule NOTIFY fillRuleChanged) + Q_PROPERTY(JoinStyle joinStyle READ joinStyle WRITE setJoinStyle NOTIFY joinStyleChanged) + Q_PROPERTY(int miterLimit READ miterLimit WRITE setMiterLimit NOTIFY miterLimitChanged) + Q_PROPERTY(CapStyle capStyle READ capStyle WRITE setCapStyle NOTIFY capStyleChanged) + Q_PROPERTY(StrokeStyle strokeStyle READ strokeStyle WRITE setStrokeStyle NOTIFY strokeStyleChanged) + Q_PROPERTY(qreal dashOffset READ dashOffset WRITE setDashOffset NOTIFY dashOffsetChanged) + Q_PROPERTY(QVector<qreal> dashPattern READ dashPattern WRITE setDashPattern NOTIFY dashPatternChanged) + Q_PROPERTY(QQuickPathGradient *fillGradient READ fillGradient WRITE setFillGradient RESET resetFillGradient) + +public: + enum FillRule { + OddEvenFill = Qt::OddEvenFill, + WindingFill = Qt::WindingFill + }; + Q_ENUM(FillRule) + + enum JoinStyle { + MiterJoin = Qt::MiterJoin, + BevelJoin = Qt::BevelJoin, + RoundJoin = Qt::RoundJoin + }; + Q_ENUM(JoinStyle) + + enum CapStyle { + FlatCap = Qt::FlatCap, + SquareCap = Qt::SquareCap, + RoundCap = Qt::RoundCap + }; + Q_ENUM(CapStyle) + + enum StrokeStyle { + SolidLine = Qt::SolidLine, + DashLine = Qt::DashLine + }; + Q_ENUM(StrokeStyle) + + enum RendererType { + UnknownRenderer, + GeometryRenderer, + NvprRenderer, + SoftwareRenderer + }; + Q_ENUM(RendererType) + + QQuickPathItem(QQuickItem *parent = nullptr); + ~QQuickPathItem(); + + RendererType rendererType() const; + + QQuickPath *path() const; + void setPath(QQuickPath *path); + + QColor strokeColor() const; + void setStrokeColor(const QColor &color); + + qreal strokeWidth() const; + void setStrokeWidth(qreal w); + + QColor fillColor() const; + void setFillColor(const QColor &color); + + FillRule fillRule() const; + void setFillRule(FillRule fillRule); + + JoinStyle joinStyle() const; + void setJoinStyle(JoinStyle style); + + int miterLimit() const; + void setMiterLimit(int limit); + + CapStyle capStyle() const; + void setCapStyle(CapStyle style); + + StrokeStyle strokeStyle() const; + void setStrokeStyle(StrokeStyle style); + + qreal dashOffset() const; + void setDashOffset(qreal offset); + + QVector<qreal> dashPattern() const; + void setDashPattern(const QVector<qreal> &array); + + QQuickPathGradient *fillGradient() const; + void setFillGradient(QQuickPathGradient *gradient); + void resetFillGradient(); + +protected: + QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override; + void updatePolish() override; + void itemChange(ItemChange change, const ItemChangeData &data) override; + +Q_SIGNALS: + void rendererChanged(); + void pathChanged(); + void strokeColorChanged(); + void strokeWidthChanged(); + void fillColorChanged(); + void fillRuleChanged(); + void joinStyleChanged(); + void miterLimitChanged(); + void capStyleChanged(); + void strokeStyleChanged(); + void dashOffsetChanged(); + void dashPatternChanged(); + void fillGradientChanged(); + +private: + Q_DISABLE_COPY(QQuickPathItem) + Q_DECLARE_PRIVATE(QQuickPathItem) + Q_PRIVATE_SLOT(d_func(), void _q_pathChanged()) + Q_PRIVATE_SLOT(d_func(), void _q_fillGradientChanged()) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickPathItem) + +#endif // QQUICKPATHITEM_P_H diff --git a/src/quick/items/qquickpathitem_p_p.h b/src/quick/items/qquickpathitem_p_p.h new file mode 100644 index 0000000000..366628d867 --- /dev/null +++ b/src/quick/items/qquickpathitem_p_p.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEM_P_P_H +#define QQUICKPATHITEM_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpathitem_p.h" +#include "qquickitem_p.h" +#include <QPainterPath> +#include <QColor> +#include <QBrush> +#include <private/qopenglcontext_p.h> + +QT_BEGIN_NAMESPACE + +class QSGPlainTexture; + +class QQuickAbstractPathRenderer +{ +public: + virtual ~QQuickAbstractPathRenderer() { } + + // Gui thread + virtual void beginSync() = 0; + virtual void setPath(const QQuickPath *path) = 0; + virtual void setStrokeColor(const QColor &color) = 0; + virtual void setStrokeWidth(qreal w) = 0; + virtual void setFillColor(const QColor &color) = 0; + virtual void setFillRule(QQuickPathItem::FillRule fillRule) = 0; + virtual void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) = 0; + virtual void setCapStyle(QQuickPathItem::CapStyle capStyle) = 0; + virtual void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) = 0; + virtual void setFillGradient(QQuickPathGradient *gradient) = 0; + virtual void endSync() = 0; + + // Render thread, with gui blocked + virtual void updatePathRenderNode() = 0; +}; + +class QQuickPathItemPrivate : public QQuickItemPrivate +{ + Q_DECLARE_PUBLIC(QQuickPathItem) + +public: + enum Dirty { + DirtyPath = 0x01, + DirtyStrokeColor = 0x02, + DirtyStrokeWidth = 0x04, + DirtyFillColor = 0x08, + DirtyFillRule = 0x10, + DirtyStyle = 0x20, + DirtyDash = 0x40, + DirtyFillGradient = 0x80, + + DirtyAll = 0xFF + }; + + QQuickPathItemPrivate(); + ~QQuickPathItemPrivate(); + + void createRenderer(); + QSGNode *createRenderNode(); + void sync(); + + void _q_pathChanged(); + void _q_fillGradientChanged(); + + QQuickPathItem::RendererType rendererType; + QQuickAbstractPathRenderer *renderer; + QQuickPath *path; + int dirty; + QColor strokeColor; + qreal strokeWidth; + QColor fillColor; + QQuickPathItem::FillRule fillRule; + QQuickPathItem::JoinStyle joinStyle; + int miterLimit; + QQuickPathItem::CapStyle capStyle; + QQuickPathItem::StrokeStyle strokeStyle; + qreal dashOffset; + QVector<qreal> dashPattern; + QQuickPathGradient *fillGradient; +}; + +#ifndef QT_NO_OPENGL + +class QQuickPathItemGradientCache : public QOpenGLSharedResource +{ +public: + struct GradientDesc { + QGradientStops stops; + QPointF start; + QPointF end; + QQuickPathGradient::SpreadMode spread; + bool operator==(const GradientDesc &other) const + { + return start == other.start && end == other.end && spread == other.spread + && stops == other.stops; + } + }; + + QQuickPathItemGradientCache(QOpenGLContext *context) : QOpenGLSharedResource(context->shareGroup()) { } + ~QQuickPathItemGradientCache(); + + void invalidateResource() override; + void freeResource(QOpenGLContext *) override; + + QSGTexture *get(const GradientDesc &grad); + + static QQuickPathItemGradientCache *currentCache(); + +private: + QHash<GradientDesc, QSGPlainTexture *> m_cache; +}; + +inline uint qHash(const QQuickPathItemGradientCache::GradientDesc &v, uint seed = 0) +{ + uint h = seed; + h += v.start.x() + v.end.y() + v.spread; + for (int i = 0; i < 3 && i < v.stops.count(); ++i) + h += v.stops[i].second.rgba(); + return h; +} + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE + +#endif diff --git a/src/quick/items/qquickpathitemgenericrenderer.cpp b/src/quick/items/qquickpathitemgenericrenderer.cpp new file mode 100644 index 0000000000..9bd03c0e51 --- /dev/null +++ b/src/quick/items/qquickpathitemgenericrenderer.cpp @@ -0,0 +1,510 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpathitemgenericrenderer_p.h" +#include <QtGui/private/qtriangulator_p.h> +#include <QSGVertexColorMaterial> + +QT_BEGIN_NAMESPACE + +static const qreal SCALE = 100; + +struct ColoredVertex // must match QSGGeometry::ColoredPoint2D +{ + float x, y; + QQuickPathItemGenericRenderer::Color4ub color; + void set(float nx, float ny, QQuickPathItemGenericRenderer::Color4ub ncolor) + { + x = nx; y = ny; color = ncolor; + } +}; + +static inline QQuickPathItemGenericRenderer::Color4ub colorToColor4ub(const QColor &c) +{ + QQuickPathItemGenericRenderer::Color4ub color = { + uchar(qRound(c.redF() * c.alphaF() * 255)), + uchar(qRound(c.greenF() * c.alphaF() * 255)), + uchar(qRound(c.blueF() * c.alphaF() * 255)), + uchar(qRound(c.alphaF() * 255)) + }; + return color; +} + +QQuickPathItemGenericRootRenderNode::QQuickPathItemGenericRootRenderNode(QQuickWindow *window, + bool hasFill, + bool hasStroke) + : m_fillNode(nullptr), + m_strokeNode(nullptr) +{ + if (hasFill) { + m_fillNode = new QQuickPathItemGenericRenderNode(window, this); + appendChildNode(m_fillNode); + } + if (hasStroke) { + m_strokeNode = new QQuickPathItemGenericRenderNode(window, this); + appendChildNode(m_strokeNode); + } +} + +QQuickPathItemGenericRootRenderNode::~QQuickPathItemGenericRootRenderNode() +{ +} + +QQuickPathItemGenericRenderNode::QQuickPathItemGenericRenderNode(QQuickWindow *window, + QQuickPathItemGenericRootRenderNode *rootNode) + : m_geometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0), + m_window(window), + m_rootNode(rootNode), + m_material(nullptr) +{ + setGeometry(&m_geometry); + activateMaterial(MatSolidColor); +} + +QQuickPathItemGenericRenderNode::~QQuickPathItemGenericRenderNode() +{ +} + +void QQuickPathItemGenericRenderNode::activateMaterial(Material m) +{ + switch (m) { + case MatSolidColor: + // Use vertexcolor material. Items with different colors remain batchable + // this way, at the expense of having to provide per-vertex color values. + if (!m_solidColorMaterial) + m_solidColorMaterial.reset(QQuickPathItemGenericMaterialFactory::createVertexColor(m_window)); + m_material = m_solidColorMaterial.data(); + break; + case MatLinearGradient: + if (!m_linearGradientMaterial) + m_linearGradientMaterial.reset(QQuickPathItemGenericMaterialFactory::createLinearGradient(m_window, this)); + m_material = m_linearGradientMaterial.data(); + break; + default: + qWarning("Unknown material %d", m); + return; + } + + if (material() != m_material) + setMaterial(m_material); +} + +// sync, and so triangulation too, happens on the gui thread +void QQuickPathItemGenericRenderer::beginSync() +{ + m_syncDirty = 0; +} + +void QQuickPathItemGenericRenderer::setPath(const QQuickPath *path) +{ + m_path = path ? path->path() : QPainterPath(); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setStrokeColor(const QColor &color) +{ + m_strokeColor = colorToColor4ub(color); + m_syncDirty |= DirtyColor; +} + +void QQuickPathItemGenericRenderer::setStrokeWidth(qreal w) +{ + m_pen.setWidthF(w); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setFillColor(const QColor &color) +{ + m_fillColor = colorToColor4ub(color); + m_syncDirty |= DirtyColor; +} + +void QQuickPathItemGenericRenderer::setFillRule(QQuickPathItem::FillRule fillRule) +{ + m_fillRule = Qt::FillRule(fillRule); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) +{ + m_pen.setJoinStyle(Qt::PenJoinStyle(joinStyle)); + m_pen.setMiterLimit(miterLimit); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setCapStyle(QQuickPathItem::CapStyle capStyle) +{ + m_pen.setCapStyle(Qt::PenCapStyle(capStyle)); + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) +{ + m_pen.setStyle(Qt::PenStyle(strokeStyle)); + if (strokeStyle == QQuickPathItem::DashLine) { + m_pen.setDashPattern(dashPattern); + m_pen.setDashOffset(dashOffset); + } + m_syncDirty |= DirtyGeom; +} + +void QQuickPathItemGenericRenderer::setFillGradient(QQuickPathGradient *gradient) +{ + m_fillGradientActive = gradient != nullptr; + if (gradient) { + m_fillGradient.stops = gradient->sortedGradientStops(); + m_fillGradient.spread = gradient->spread(); + if (QQuickPathLinearGradient *g = qobject_cast<QQuickPathLinearGradient *>(gradient)) { + m_fillGradient.start = QPointF(g->x1(), g->y1()); + m_fillGradient.end = QPointF(g->x2(), g->y2()); + } else { + Q_UNREACHABLE(); + } + } + m_syncDirty |= DirtyFillGradient; +} + +void QQuickPathItemGenericRenderer::endSync() +{ + if (!m_syncDirty) + return; + + // Use a shadow dirty flag in order to avoid losing state in case there are + // multiple syncs with different dirty flags before we get to + // updatePathRenderNode() on the render thread (with the gui thread + // blocked). For our purposes here m_syncDirty is still required since + // geometry regeneration must only happen when there was an actual change + // in this particular sync round. + m_effectiveDirty |= m_syncDirty; + + if (m_path.isEmpty()) { + m_fillVertices.clear(); + m_fillIndices.clear(); + m_strokeVertices.clear(); + return; + } + + triangulateFill(); + triangulateStroke(); +} + +void QQuickPathItemGenericRenderer::triangulateFill() +{ + m_path.setFillRule(m_fillRule); + + const QVectorPath &vp = qtVectorPathForPath(m_path); + + QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(SCALE, SCALE)); + const int vertexCount = ts.vertices.count() / 2; // just a qreal vector with x,y hence the / 2 + m_fillVertices.resize(vertexCount); + ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(m_fillVertices.data()); + const qreal *vsrc = ts.vertices.constData(); + for (int i = 0; i < vertexCount; ++i) + vdst[i].set(vsrc[i * 2] / SCALE, vsrc[i * 2 + 1] / SCALE, m_fillColor); + + m_fillIndices.resize(ts.indices.size()); + quint16 *idst = m_fillIndices.data(); + if (ts.indices.type() == QVertexIndexVector::UnsignedShort) { + memcpy(idst, ts.indices.data(), m_fillIndices.count() * sizeof(quint16)); + } else { + const quint32 *isrc = (const quint32 *) ts.indices.data(); + for (int i = 0; i < m_fillIndices.count(); ++i) + idst[i] = isrc[i]; + } +} + +void QQuickPathItemGenericRenderer::triangulateStroke() +{ + const QVectorPath &vp = qtVectorPathForPath(m_path); + + const QRectF clip(0, 0, m_item->width(), m_item->height()); + const qreal inverseScale = 1.0 / SCALE; + m_stroker.setInvScale(inverseScale); + if (m_pen.style() == Qt::SolidLine) { + m_stroker.process(vp, m_pen, clip, 0); + } else { + m_dashStroker.setInvScale(inverseScale); + m_dashStroker.process(vp, m_pen, clip, 0); + QVectorPath dashStroke(m_dashStroker.points(), m_dashStroker.elementCount(), + m_dashStroker.elementTypes(), 0); + m_stroker.process(dashStroke, m_pen, clip, 0); + } + + if (!m_stroker.vertexCount()) { + m_strokeVertices.clear(); + return; + } + + const int vertexCount = m_stroker.vertexCount() / 2; // just a float vector with x,y hence the / 2 + m_strokeVertices.resize(vertexCount); + ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(m_strokeVertices.data()); + const float *vsrc = m_stroker.vertices(); + for (int i = 0; i < vertexCount; ++i) + vdst[i].set(vsrc[i * 2], vsrc[i * 2 + 1], m_strokeColor); +} + +void QQuickPathItemGenericRenderer::setRootNode(QQuickPathItemGenericRootRenderNode *rn) +{ + if (m_rootNode != rn) { + m_rootNode = rn; + // Scenegraph nodes can be destroyed and then replaced by new ones over + // time; hence it is important to mark everything dirty for + // updatePathRenderNode(). We can assume the renderer has a full sync + // of the data at this point. + m_effectiveDirty = DirtyAll; + } +} + +// on the render thread with gui blocked +void QQuickPathItemGenericRenderer::updatePathRenderNode() +{ + if (!m_effectiveDirty || !m_rootNode) + return; + + if (m_fillColor.a == 0) { + delete m_rootNode->m_fillNode; + m_rootNode->m_fillNode = nullptr; + } else if (!m_rootNode->m_fillNode) { + m_rootNode->m_fillNode = new QQuickPathItemGenericRenderNode(m_item->window(), m_rootNode); + if (m_rootNode->m_strokeNode) + m_rootNode->removeChildNode(m_rootNode->m_strokeNode); + m_rootNode->appendChildNode(m_rootNode->m_fillNode); + if (m_rootNode->m_strokeNode) + m_rootNode->appendChildNode(m_rootNode->m_strokeNode); + m_effectiveDirty |= DirtyGeom; + } + + if (qFuzzyIsNull(m_pen.widthF()) || m_strokeColor.a == 0) { + delete m_rootNode->m_strokeNode; + m_rootNode->m_strokeNode = nullptr; + } else if (!m_rootNode->m_strokeNode) { + m_rootNode->m_strokeNode = new QQuickPathItemGenericRenderNode(m_item->window(), m_rootNode); + m_rootNode->appendChildNode(m_rootNode->m_strokeNode); + m_effectiveDirty |= DirtyGeom; + } + + updateFillNode(); + updateStrokeNode(); + + m_effectiveDirty = 0; +} + +void QQuickPathItemGenericRenderer::updateFillNode() +{ + if (!m_rootNode->m_fillNode) + return; + + QQuickPathItemGenericRenderNode *n = m_rootNode->m_fillNode; + QSGGeometry *g = &n->m_geometry; + if (m_fillVertices.isEmpty()) { + g->allocate(0, 0); + n->markDirty(QSGNode::DirtyGeometry); + return; + } + + if (m_fillGradientActive) { + n->activateMaterial(QQuickPathItemGenericRenderNode::MatLinearGradient); + if (m_effectiveDirty & DirtyFillGradient) { + // Make a copy of the data that will be accessed by the material on + // the render thread. + n->m_fillGradient = m_fillGradient; + // Gradients are implemented via a texture-based material. + n->markDirty(QSGNode::DirtyMaterial); + // stop here if only the gradient changed; no need to touch the geometry + if (!(m_effectiveDirty & DirtyGeom)) + return; + } + } else { + n->activateMaterial(QQuickPathItemGenericRenderNode::MatSolidColor); + // fast path for updating only color values when no change in vertex positions + if ((m_effectiveDirty & DirtyColor) && !(m_effectiveDirty & DirtyGeom)) { + ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData()); + for (int i = 0; i < g->vertexCount(); ++i) + vdst[i].set(vdst[i].x, vdst[i].y, m_fillColor); + n->markDirty(QSGNode::DirtyGeometry); + return; + } + } + + g->allocate(m_fillVertices.count(), m_fillIndices.count()); + g->setDrawingMode(QSGGeometry::DrawTriangles); + memcpy(g->vertexData(), m_fillVertices.constData(), g->vertexCount() * g->sizeOfVertex()); + memcpy(g->indexData(), m_fillIndices.constData(), g->indexCount() * g->sizeOfIndex()); + + n->markDirty(QSGNode::DirtyGeometry); +} + +void QQuickPathItemGenericRenderer::updateStrokeNode() +{ + if (!m_rootNode->m_strokeNode) + return; + if (m_effectiveDirty == DirtyFillGradient) // not applicable + return; + + QQuickPathItemGenericRenderNode *n = m_rootNode->m_strokeNode; + n->markDirty(QSGNode::DirtyGeometry); + + QSGGeometry *g = &n->m_geometry; + if (m_strokeVertices.isEmpty()) { + g->allocate(0, 0); + return; + } + + if ((m_effectiveDirty & DirtyColor) && !(m_effectiveDirty & DirtyGeom)) { + ColoredVertex *vdst = reinterpret_cast<ColoredVertex *>(g->vertexData()); + for (int i = 0; i < g->vertexCount(); ++i) + vdst[i].set(vdst[i].x, vdst[i].y, m_strokeColor); + return; + } + + g->allocate(m_strokeVertices.count(), 0); + g->setDrawingMode(QSGGeometry::DrawTriangleStrip); + memcpy(g->vertexData(), m_strokeVertices.constData(), g->vertexCount() * g->sizeOfVertex()); +} + +QSGMaterial *QQuickPathItemGenericMaterialFactory::createVertexColor(QQuickWindow *window) +{ + QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); + +#ifndef QT_NO_OPENGL + if (api == QSGRendererInterface::OpenGL) // ### so much for "generic"... + return new QSGVertexColorMaterial; +#endif + + qWarning("Vertex-color material: Unsupported graphics API %d", api); + return nullptr; +} + +QSGMaterial *QQuickPathItemGenericMaterialFactory::createLinearGradient(QQuickWindow *window, + QQuickPathItemGenericRenderNode *node) +{ + QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); + +#ifndef QT_NO_OPENGL + if (api == QSGRendererInterface::OpenGL) // ### so much for "generic"... + return new QQuickPathItemLinearGradientMaterial(node); +#endif + + qWarning("Linear gradient material: Unsupported graphics API %d", api); + return nullptr; +} + +#ifndef QT_NO_OPENGL + +QSGMaterialType QQuickPathItemLinearGradientShader::type; + +QQuickPathItemLinearGradientShader::QQuickPathItemLinearGradientShader() +{ + setShaderSourceFile(QOpenGLShader::Vertex, + QStringLiteral(":/qt-project.org/items/shaders/lineargradient.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, + QStringLiteral(":/qt-project.org/items/shaders/lineargradient.frag")); +} + +void QQuickPathItemLinearGradientShader::initialize() +{ + m_opacityLoc = program()->uniformLocation("opacity"); + m_matrixLoc = program()->uniformLocation("matrix"); + m_gradStartLoc = program()->uniformLocation("gradStart"); + m_gradEndLoc = program()->uniformLocation("gradEnd"); +} + +void QQuickPathItemLinearGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *) +{ + QQuickPathItemLinearGradientMaterial *m = static_cast<QQuickPathItemLinearGradientMaterial *>(mat); + + if (state.isOpacityDirty()) + program()->setUniformValue(m_opacityLoc, state.opacity()); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrixLoc, state.combinedMatrix()); + + QQuickPathItemGenericRenderNode *node = m->node(); + program()->setUniformValue(m_gradStartLoc, QVector2D(node->m_fillGradient.start)); + program()->setUniformValue(m_gradEndLoc, QVector2D(node->m_fillGradient.end)); + + QSGTexture *tx = QQuickPathItemGradientCache::currentCache()->get(node->m_fillGradient); + tx->bind(); +} + +char const *const *QQuickPathItemLinearGradientShader::attributeNames() const +{ + static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr }; + return attr; +} + +int QQuickPathItemLinearGradientMaterial::compare(const QSGMaterial *other) const +{ + Q_ASSERT(other && type() == other->type()); + const QQuickPathItemLinearGradientMaterial *m = static_cast<const QQuickPathItemLinearGradientMaterial *>(other); + + QQuickPathItemGenericRenderNode *a = node(); + QQuickPathItemGenericRenderNode *b = m->node(); + Q_ASSERT(a && b); + if (a == b) + return 0; + + const QQuickPathItemGradientCache::GradientDesc *ga = &a->m_fillGradient; + const QQuickPathItemGradientCache::GradientDesc *gb = &b->m_fillGradient; + if (int d = ga->start.x() - gb->start.x()) + return d; + if (int d = ga->start.y() - gb->start.y()) + return d; + if (int d = ga->end.x() - gb->end.x()) + return d; + if (int d = ga->end.y() - gb->end.y()) + return d; + + if (int d = ga->stops.count() - gb->stops.count()) + return d; + + for (int i = 0; i < ga->stops.count(); ++i) { + if (int d = ga->stops[i].first - gb->stops[i].first) + return d; + if (int d = ga->stops[i].second.rgba() - gb->stops[i].second.rgba()) + return d; + } + + return 0; +} + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE diff --git a/src/quick/items/qquickpathitemgenericrenderer_p.h b/src/quick/items/qquickpathitemgenericrenderer_p.h new file mode 100644 index 0000000000..c186959c88 --- /dev/null +++ b/src/quick/items/qquickpathitemgenericrenderer_p.h @@ -0,0 +1,232 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEMGENERICRENDERER_P_H +#define QQUICKPATHITEMGENERICRENDERER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpathitem_p_p.h" +#include <qsgnode.h> +#include <qsggeometry.h> +#include <qsgmaterial.h> +#include <QtGui/private/qtriangulatingstroker_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickPathItemGenericRootRenderNode; + +class QQuickPathItemGenericRenderer : public QQuickAbstractPathRenderer +{ +public: + enum Dirty { + DirtyGeom = 0x01, + DirtyColor = 0x02, + DirtyFillGradient = 0x04, + + DirtyAll = 0xFF + }; + + QQuickPathItemGenericRenderer(QQuickItem *item) + : m_item(item), + m_rootNode(nullptr), + m_effectiveDirty(0) + { } + + void beginSync() override; + void setPath(const QQuickPath *path) override; + void setStrokeColor(const QColor &color) override; + void setStrokeWidth(qreal w) override; + void setFillColor(const QColor &color) override; + void setFillRule(QQuickPathItem::FillRule fillRule) override; + void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) override; + void setCapStyle(QQuickPathItem::CapStyle capStyle) override; + void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) override; + void setFillGradient(QQuickPathGradient *gradient) override; + void endSync() override; + void updatePathRenderNode() override; + + void setRootNode(QQuickPathItemGenericRootRenderNode *rn); + + struct Color4ub { unsigned char r, g, b, a; }; + +private: + void triangulateFill(); + void triangulateStroke(); + void updateFillNode(); + void updateStrokeNode(); + + QQuickItem *m_item; + QQuickPathItemGenericRootRenderNode *m_rootNode; + QTriangulatingStroker m_stroker; + QDashedStrokeProcessor m_dashStroker; + + QPen m_pen; + Color4ub m_strokeColor; + Color4ub m_fillColor; + Qt::FillRule m_fillRule; + QPainterPath m_path; + bool m_fillGradientActive; + QQuickPathItemGradientCache::GradientDesc m_fillGradient; + + QVector<QSGGeometry::ColoredPoint2D> m_fillVertices; + QVector<quint16> m_fillIndices; + QVector<QSGGeometry::ColoredPoint2D> m_strokeVertices; + + int m_syncDirty; + int m_effectiveDirty; +}; + +class QQuickPathItemGenericRenderNode : public QSGGeometryNode +{ +public: + QQuickPathItemGenericRenderNode(QQuickWindow *window, QQuickPathItemGenericRootRenderNode *rootNode); + ~QQuickPathItemGenericRenderNode(); + + enum Material { + MatSolidColor, + MatLinearGradient + }; + + void activateMaterial(Material m); + + QQuickWindow *window() const { return m_window; } + QQuickPathItemGenericRootRenderNode *rootNode() const { return m_rootNode; } + + // shadow data for custom materials + QQuickPathItemGradientCache::GradientDesc m_fillGradient; + +private: + QSGGeometry m_geometry; + QQuickWindow *m_window; + QQuickPathItemGenericRootRenderNode *m_rootNode; + QSGMaterial *m_material; + QScopedPointer<QSGMaterial> m_solidColorMaterial; + QScopedPointer<QSGMaterial> m_linearGradientMaterial; + + friend class QQuickPathItemGenericRenderer; +}; + +class QQuickPathItemGenericRootRenderNode : public QSGNode +{ +public: + QQuickPathItemGenericRootRenderNode(QQuickWindow *window, bool hasFill, bool hasStroke); + ~QQuickPathItemGenericRootRenderNode(); + +private: + QQuickPathItemGenericRenderNode *m_fillNode; + QQuickPathItemGenericRenderNode *m_strokeNode; + + friend class QQuickPathItemGenericRenderer; +}; + +class QQuickPathItemGenericMaterialFactory +{ +public: + static QSGMaterial *createVertexColor(QQuickWindow *window); + static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickPathItemGenericRenderNode *node); +}; + +#ifndef QT_NO_OPENGL + +class QQuickPathItemLinearGradientShader : public QSGMaterialShader +{ +public: + QQuickPathItemLinearGradientShader(); + + void initialize() override; + void updateState(const RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override; + char const *const *attributeNames() const override; + + static QSGMaterialType type; + +private: + int m_opacityLoc; + int m_matrixLoc; + int m_gradStartLoc; + int m_gradEndLoc; +}; + +class QQuickPathItemLinearGradientMaterial : public QSGMaterial +{ +public: + QQuickPathItemLinearGradientMaterial(QQuickPathItemGenericRenderNode *node) + : m_node(node) + { + // Passing RequiresFullMatrix is essential in order to prevent the + // batch renderer from baking in simple, translate-only transforms into + // the vertex data. The shader will rely on the fact that + // vertexCoord.xy is the PathItem-space coordinate and so no modifications + // are welcome. + setFlag(Blending | RequiresFullMatrix); + } + + QSGMaterialType *type() const override + { + return &QQuickPathItemLinearGradientShader::type; + } + + int compare(const QSGMaterial *other) const override; + + QSGMaterialShader *createShader() const override + { + return new QQuickPathItemLinearGradientShader; + } + + QQuickPathItemGenericRenderNode *node() const { return m_node; } + +private: + QQuickPathItemGenericRenderNode *m_node; +}; + +#endif // QT_NO_OPENGL + +QT_END_NAMESPACE + +#endif // QQUICKPATHITEMGENERICRENDERER_P_H diff --git a/src/quick/items/qquickpathitemnvprrenderer.cpp b/src/quick/items/qquickpathitemnvprrenderer.cpp new file mode 100644 index 0000000000..d07a63c86d --- /dev/null +++ b/src/quick/items/qquickpathitemnvprrenderer.cpp @@ -0,0 +1,567 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpathitemnvprrenderer_p.h" +#include <QOpenGLExtraFunctions> +#include <private/qquickpath_p_p.h> + +QT_BEGIN_NAMESPACE + +void QQuickPathItemNvprRenderer::beginSync() +{ + // nothing to do here +} + +void QQuickPathItemNvprRenderer::setPath(const QQuickPath *path) +{ + convertPath(path); + m_dirty |= DirtyPath; +} + +void QQuickPathItemNvprRenderer::setStrokeColor(const QColor &color) +{ + m_strokeColor = color; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setStrokeWidth(qreal w) +{ + m_strokeWidth = w; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setFillColor(const QColor &color) +{ + m_fillColor = color; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setFillRule(QQuickPathItem::FillRule fillRule) +{ + m_fillRule = fillRule; + m_dirty |= DirtyFillRule; +} + +void QQuickPathItemNvprRenderer::setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) +{ + m_joinStyle = joinStyle; + m_miterLimit = miterLimit; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setCapStyle(QQuickPathItem::CapStyle capStyle) +{ + m_capStyle = capStyle; + m_dirty |= DirtyStyle; +} + +void QQuickPathItemNvprRenderer::setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) +{ + m_dashActive = strokeStyle == QQuickPathItem::DashLine; + m_dashOffset = dashOffset; + m_dashPattern = dashPattern; + m_dirty |= DirtyDash; +} + +void QQuickPathItemNvprRenderer::setFillGradient(QQuickPathGradient *gradient) +{ + m_fillGradientActive = gradient != nullptr; + if (gradient) { + m_fillGradient.stops = gradient->sortedGradientStops(); + m_fillGradient.spread = gradient->spread(); + if (QQuickPathLinearGradient *g = qobject_cast<QQuickPathLinearGradient *>(gradient)) { + m_fillGradient.start = QPointF(g->x1(), g->y1()); + m_fillGradient.end = QPointF(g->x2(), g->y2()); + } else { + Q_UNREACHABLE(); + } + } + m_dirty |= DirtyFillGradient; +} + +void QQuickPathItemNvprRenderer::endSync() +{ + // nothing to do here +} + +void QQuickPathItemNvprRenderer::setNode(QQuickPathItemNvprRenderNode *node) +{ + if (m_node != node) { + m_node = node; + // Scenegraph nodes can be destroyed and then replaced by new ones over + // time; hence it is important to mark everything dirty for + // updatePathRenderNode(). We can assume the renderer has a full sync + // of the data at this point. + m_dirty = DirtyAll; + } +} + +QDebug operator<<(QDebug debug, const QQuickPathItemNvprRenderer::NvprPath &path) +{ + QDebugStateSaver saver(debug); + debug.space().noquote(); + debug << "Path with" << path.cmd.count() << "commands"; + int ci = 0; + for (GLubyte cmd : path.cmd) { + static struct { GLubyte cmd; const char *s; int coordCount; } nameTab[] = { + { GL_MOVE_TO_NV, "moveTo", 2 }, + { GL_LINE_TO_NV, "lineTo", 2 }, + { GL_QUADRATIC_CURVE_TO_NV, "quadTo", 4 }, + { GL_CUBIC_CURVE_TO_NV, "cubicTo", 6 }, + { GL_LARGE_CW_ARC_TO_NV, "arcTo-large-CW", 5 }, + { GL_LARGE_CCW_ARC_TO_NV, "arcTo-large-CCW", 5 }, + { GL_SMALL_CW_ARC_TO_NV, "arcTo-small-CW", 5 }, + { GL_SMALL_CCW_ARC_TO_NV, "arcTo-small-CCW", 5 }, + { GL_CLOSE_PATH_NV, "closePath", 0 } }; + for (size_t i = 0; i < sizeof(nameTab) / sizeof(nameTab[0]); ++i) { + if (nameTab[i].cmd == cmd) { + QByteArray cs; + for (int j = 0; j < nameTab[i].coordCount; ++j) { + cs.append(QByteArray::number(path.coord[ci++])); + cs.append(' '); + } + debug << "\n " << nameTab[i].s << " " << cs; + break; + } + } + } + return debug; +} + +static inline void appendCoords(QVector<GLfloat> *v, QQuickCurve *c, QPointF *pos) +{ + QPointF p(c->hasRelativeX() ? pos->x() + c->relativeX() : c->x(), + c->hasRelativeY() ? pos->y() + c->relativeY() : c->y()); + v->append(p.x()); + v->append(p.y()); + *pos = p; +} + +static inline void appendControlCoords(QVector<GLfloat> *v, QQuickPathQuad *c, const QPointF &pos) +{ + QPointF p(c->hasRelativeControlX() ? pos.x() + c->relativeControlX() : c->controlX(), + c->hasRelativeControlY() ? pos.y() + c->relativeControlY() : c->controlY()); + v->append(p.x()); + v->append(p.y()); +} + +static inline void appendControl1Coords(QVector<GLfloat> *v, QQuickPathCubic *c, const QPointF &pos) +{ + QPointF p(c->hasRelativeControl1X() ? pos.x() + c->relativeControl1X() : c->control1X(), + c->hasRelativeControl1Y() ? pos.y() + c->relativeControl1Y() : c->control1Y()); + v->append(p.x()); + v->append(p.y()); +} + +static inline void appendControl2Coords(QVector<GLfloat> *v, QQuickPathCubic *c, const QPointF &pos) +{ + QPointF p(c->hasRelativeControl2X() ? pos.x() + c->relativeControl2X() : c->control2X(), + c->hasRelativeControl2Y() ? pos.y() + c->relativeControl2Y() : c->control2Y()); + v->append(p.x()); + v->append(p.y()); +} + +void QQuickPathItemNvprRenderer::convertPath(const QQuickPath *path) +{ + m_path = NvprPath(); + if (!path) + return; + + const QList<QQuickPathElement *> &pp(QQuickPathPrivate::get(path)->_pathElements); + if (pp.isEmpty()) + return; + + QPointF pos(path->startX(), path->startY()); + m_path.cmd.append(GL_MOVE_TO_NV); + m_path.coord.append(pos.x()); + m_path.coord.append(pos.y()); + + for (QQuickPathElement *e : pp) { + if (QQuickPathMove *o = qobject_cast<QQuickPathMove *>(e)) { + m_path.cmd.append(GL_MOVE_TO_NV); + appendCoords(&m_path.coord, o, &pos); + } else if (QQuickPathLine *o = qobject_cast<QQuickPathLine *>(e)) { + m_path.cmd.append(GL_LINE_TO_NV); + appendCoords(&m_path.coord, o, &pos); + } else if (QQuickPathQuad *o = qobject_cast<QQuickPathQuad *>(e)) { + m_path.cmd.append(GL_QUADRATIC_CURVE_TO_NV); + appendControlCoords(&m_path.coord, o, pos); + appendCoords(&m_path.coord, o, &pos); + } else if (QQuickPathCubic *o = qobject_cast<QQuickPathCubic *>(e)) { + m_path.cmd.append(GL_CUBIC_CURVE_TO_NV); + appendControl1Coords(&m_path.coord, o, pos); + appendControl2Coords(&m_path.coord, o, pos); + appendCoords(&m_path.coord, o, &pos); + } else if (QQuickPathArc *o = qobject_cast<QQuickPathArc *>(e)) { + const bool sweepFlag = o->direction() == QQuickPathArc::Clockwise; // maps to CCW, not a typo + GLenum cmd; + if (o->useLargeArc()) + cmd = sweepFlag ? GL_LARGE_CCW_ARC_TO_NV : GL_LARGE_CW_ARC_TO_NV; + else + cmd = sweepFlag ? GL_SMALL_CCW_ARC_TO_NV : GL_SMALL_CW_ARC_TO_NV; + m_path.cmd.append(cmd); + m_path.coord.append(o->radiusX()); + m_path.coord.append(o->radiusY()); + m_path.coord.append(0.0f); // X axis rotation + appendCoords(&m_path.coord, o, &pos); + } else { + qWarning() << "PathItem/NVPR: unsupported Path element" << e; + } + } + + if (qFuzzyCompare(pos.x(), path->startX()) && qFuzzyCompare(pos.y(), path->startY())) + m_path.cmd.append(GL_CLOSE_PATH_NV); +} + +static inline QVector4D qsg_premultiply(const QColor &c, float globalOpacity) +{ + const float o = c.alphaF() * globalOpacity; + return QVector4D(c.redF() * o, c.greenF() * o, c.blueF() * o, o); +} + +void QQuickPathItemNvprRenderer::updatePathRenderNode() +{ + // Called on the render thread with gui blocked -> update the node with its + // own copy of all relevant data. + + if (!m_dirty) + return; + + // updatePathRenderNode() can be called several times with different dirty + // state before render() gets invoked. So accumulate. + m_node->m_dirty |= m_dirty; + + if (m_dirty & DirtyPath) + m_node->m_source = m_path; + + if (m_dirty & DirtyStyle) { + m_node->m_strokeWidth = m_strokeWidth; + m_node->m_strokeColor = qsg_premultiply(m_strokeColor, 1.0f); + m_node->m_fillColor = qsg_premultiply(m_fillColor, 1.0f); + switch (m_joinStyle) { + case QQuickPathItem::MiterJoin: + m_node->m_joinStyle = GL_MITER_TRUNCATE_NV; + break; + case QQuickPathItem::BevelJoin: + m_node->m_joinStyle = GL_BEVEL_NV; + break; + case QQuickPathItem::RoundJoin: + m_node->m_joinStyle = GL_ROUND_NV; + break; + default: + Q_UNREACHABLE(); + } + m_node->m_miterLimit = m_miterLimit; + switch (m_capStyle) { + case QQuickPathItem::FlatCap: + m_node->m_capStyle = GL_FLAT; + break; + case QQuickPathItem::SquareCap: + m_node->m_capStyle = GL_SQUARE_NV; + break; + case QQuickPathItem::RoundCap: + m_node->m_capStyle = GL_ROUND_NV; + break; + default: + Q_UNREACHABLE(); + } + } + + if (m_dirty & DirtyFillRule) { + switch (m_fillRule) { + case QQuickPathItem::OddEvenFill: + m_node->m_fillRule = GL_COUNT_UP_NV; + break; + case QQuickPathItem::WindingFill: + m_node->m_fillRule = GL_INVERT; + break; + default: + Q_UNREACHABLE(); + } + } + + if (m_dirty & DirtyDash) { + m_node->m_dashOffset = m_dashOffset; + if (m_dashActive) { + m_node->m_dashPattern.resize(m_dashPattern.count()); + // Multiply by strokeWidth because the PathItem API follows QPen + // meaning the input dash pattern here is in width units. + for (int i = 0; i < m_dashPattern.count(); ++i) + m_node->m_dashPattern[i] = GLfloat(m_dashPattern[i]) * m_strokeWidth; + } else { + m_node->m_dashPattern.clear(); + } + } + + if (m_dirty & DirtyFillGradient) { + m_node->m_fillGradientActive = m_fillGradientActive; + if (m_fillGradientActive) + m_node->m_fillGradient = m_fillGradient; + } + + m_node->markDirty(QSGNode::DirtyMaterial); + m_dirty = 0; +} + +bool QQuickPathItemNvprRenderNode::nvprInited = false; +QQuickNvprFunctions QQuickPathItemNvprRenderNode::nvpr; +QQuickNvprMaterialManager QQuickPathItemNvprRenderNode::mtlmgr; + +QQuickPathItemNvprRenderNode::QQuickPathItemNvprRenderNode(QQuickPathItem *item) + : m_item(item) +{ +} + +QQuickPathItemNvprRenderNode::~QQuickPathItemNvprRenderNode() +{ + releaseResources(); +} + +void QQuickPathItemNvprRenderNode::releaseResources() +{ + if (m_path) { + nvpr.deletePaths(m_path, 1); + m_path = 0; + } +} + +void QQuickNvprMaterialManager::create(QQuickNvprFunctions *nvpr) +{ + m_nvpr = nvpr; +} + +void QQuickNvprMaterialManager::releaseResources() +{ + QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); + for (MaterialDesc &mtl : m_materials) { + if (mtl.ppl) { + f->glDeleteProgramPipelines(1, &mtl.ppl); + mtl = MaterialDesc(); + } + } +} + +QQuickNvprMaterialManager::MaterialDesc *QQuickNvprMaterialManager::activateMaterial(Material m) +{ + QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); + MaterialDesc &mtl(m_materials[m]); + + if (!mtl.ppl) { + if (m == MatSolid) { + static const char *fragSrc = + "#version 310 es\n" + "precision highp float;\n" + "out vec4 fragColor;\n" + "uniform vec4 color;\n" + "uniform float opacity;\n" + "void main() {\n" + " fragColor = color * opacity;\n" + "}\n"; + if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) { + qWarning("NVPR: Failed to create shader pipeline for solid fill"); + return nullptr; + } + Q_ASSERT(mtl.ppl && mtl.prg); + mtl.uniLoc[0] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "color"); + Q_ASSERT(mtl.uniLoc[0] >= 0); + mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity"); + Q_ASSERT(mtl.uniLoc[1] >= 0); + } else if (m == MatLinearGradient) { + static const char *fragSrc = + "#version 310 es\n" + "precision highp float;\n" + "layout(location = 0) in vec2 uv;" + "uniform float opacity;\n" + "uniform sampler2D gradTab;\n" + "uniform vec2 gradStart;\n" + "uniform vec2 gradEnd;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " vec2 gradVec = gradEnd - gradStart;\n" + " float gradTabIndex = dot(gradVec, uv - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y);\n" + " fragColor = texture(gradTab, vec2(gradTabIndex, 0.5)) * opacity;\n" + "}\n"; + if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) { + qWarning("NVPR: Failed to create shader pipeline for linear gradient"); + return nullptr; + } + Q_ASSERT(mtl.ppl && mtl.prg); + mtl.uniLoc[1] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "opacity"); + Q_ASSERT(mtl.uniLoc[1] >= 0); + mtl.uniLoc[2] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "gradStart"); + Q_ASSERT(mtl.uniLoc[2] >= 0); + mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "gradEnd"); + Q_ASSERT(mtl.uniLoc[3] >= 0); + } else { + Q_UNREACHABLE(); + } + } + + f->glBindProgramPipeline(mtl.ppl); + + return &mtl; +} + +void QQuickPathItemNvprRenderNode::updatePath() +{ + if (m_dirty & QQuickPathItemNvprRenderer::DirtyPath) { + if (!m_path) { + m_path = nvpr.genPaths(1); + Q_ASSERT(m_path != 0); + } + nvpr.pathCommands(m_path, m_source.cmd.count(), m_source.cmd.constData(), + m_source.coord.count(), GL_FLOAT, m_source.coord.constData()); + } + + if (m_dirty & QQuickPathItemNvprRenderer::DirtyStyle) { + nvpr.pathParameterf(m_path, GL_PATH_STROKE_WIDTH_NV, m_strokeWidth); + nvpr.pathParameteri(m_path, GL_PATH_JOIN_STYLE_NV, m_joinStyle); + nvpr.pathParameteri(m_path, GL_PATH_MITER_LIMIT_NV, m_miterLimit); + nvpr.pathParameteri(m_path, GL_PATH_END_CAPS_NV, m_capStyle); + nvpr.pathParameteri(m_path, GL_PATH_DASH_CAPS_NV, m_capStyle); + } + + if (m_dirty & QQuickPathItemNvprRenderer::DirtyDash) { + nvpr.pathParameterf(m_path, GL_PATH_DASH_OFFSET_NV, m_dashOffset); + // count == 0 -> no dash + nvpr.pathDashArray(m_path, m_dashPattern.count(), m_dashPattern.constData()); + } +} + +void QQuickPathItemNvprRenderNode::render(const RenderState *state) +{ + if (!nvprInited) { + if (!nvpr.create()) { + qWarning("NVPR init failed"); + return; + } + mtlmgr.create(&nvpr); + nvprInited = true; + } + + updatePath(); + + QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); + f->glUseProgram(0); + QQuickNvprMaterialManager::MaterialDesc *mtl; + if (m_fillGradientActive) + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatLinearGradient); + else + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid); + if (!mtl) + return; + + // Assume stencil buffer is cleared to 0 for each frame. + // Within the frame dppass=GL_ZERO for glStencilOp ensures stencil is reset and so no need to clear. + f->glStencilMask(~0); + f->glEnable(GL_STENCIL_TEST); + f->glStencilFunc(GL_NOTEQUAL, 0, 0xFF); + f->glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + + // Depth test against the opaque batches rendered before. + f->glEnable(GL_DEPTH_TEST); + f->glDepthFunc(GL_LESS); + nvpr.pathCoverDepthFunc(GL_LESS); + nvpr.pathStencilDepthOffset(-0.05f, -1); + + nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, matrix()->constData()); + nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, state->projectionMatrix()->constData()); + + if (state->scissorEnabled()) { + // scissor rect is already set, just enable scissoring + f->glEnable(GL_SCISSOR_TEST); + } + + if (!qFuzzyIsNull(m_fillColor.w()) || m_fillGradientActive) { + if (m_fillGradientActive) { + QSGTexture *tx = QQuickPathItemGradientCache::currentCache()->get(m_fillGradient); + tx->bind(); + // uv = vec2(coeff[0] * x + coeff[1] * y + coeff[2], coeff[3] * x + coeff[4] * y + coeff[5]) + // where x and y are in path coordinate space, which is just what + // we need since the gradient's start and stop are in that space too. + GLfloat coeff[6] = { 1, 0, 0, + 0, 1, 0 }; + nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff); + f->glProgramUniform2f(mtl->prg, mtl->uniLoc[2], m_fillGradient.start.x(), m_fillGradient.start.y()); + f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], m_fillGradient.end.x(), m_fillGradient.end.y()); + } else { + f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0], + m_fillColor.x(), m_fillColor.y(), m_fillColor.z(), m_fillColor.w()); + } + f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity()); + nvpr.stencilThenCoverFillPath(m_path, m_fillRule, 0xFF, GL_BOUNDING_BOX_NV); + } + + if (!qFuzzyIsNull(m_strokeWidth) && !qFuzzyIsNull(m_strokeColor.w())) { + if (m_fillGradientActive) + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid); + f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0], + m_strokeColor.x(), m_strokeColor.y(), m_strokeColor.z(), m_strokeColor.w()); + f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity()); + nvpr.stencilThenCoverStrokePath(m_path, 0x1, ~0, GL_CONVEX_HULL_NV); + } + + f->glBindProgramPipeline(0); + + m_dirty = 0; +} + +QSGRenderNode::StateFlags QQuickPathItemNvprRenderNode::changedStates() const +{ + return BlendState | StencilState | DepthState | ScissorState; +} + +QSGRenderNode::RenderingFlags QQuickPathItemNvprRenderNode::flags() const +{ + return DepthAwareRendering; // avoid hitting the less optimal no-opaque-batch path in the renderer +} + +QRectF QQuickPathItemNvprRenderNode::rect() const +{ + return QRect(0, 0, m_item->width(), m_item->height()); +} + +bool QQuickPathItemNvprRenderNode::isSupported() +{ + static const bool nvprDisabled = qEnvironmentVariableIntValue("QT_NO_NVPR") != 0; + return !nvprDisabled && QQuickNvprFunctions::isSupported(); +} + +QT_END_NAMESPACE diff --git a/src/quick/items/qquickpathitemnvprrenderer_p.h b/src/quick/items/qquickpathitemnvprrenderer_p.h new file mode 100644 index 0000000000..0075572324 --- /dev/null +++ b/src/quick/items/qquickpathitemnvprrenderer_p.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEMNVPRRENDERER_P_H +#define QQUICKPATHITEMNVPRRENDERER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpathitem_p_p.h" +#include <qsgrendernode.h> +#include <private/qquicknvprfunctions_p.h> +#include <QColor> +#include <QVector4D> +#include <QDebug> + +#ifndef QT_NO_OPENGL + +QT_BEGIN_NAMESPACE + +class QQuickPathItemNvprRenderNode; + +class QQuickPathItemNvprRenderer : public QQuickAbstractPathRenderer +{ +public: + enum Dirty { + DirtyPath = 0x01, + DirtyStyle = 0x02, + DirtyFillRule = 0x04, + DirtyDash = 0x08, + DirtyFillGradient = 0x10, + + DirtyAll = 0xFF + }; + + void beginSync() override; + void setPath(const QQuickPath *path) override; + void setStrokeColor(const QColor &color) override; + void setStrokeWidth(qreal w) override; + void setFillColor(const QColor &color) override; + void setFillRule(QQuickPathItem::FillRule fillRule) override; + void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) override; + void setCapStyle(QQuickPathItem::CapStyle capStyle) override; + void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) override; + void setFillGradient(QQuickPathGradient *gradient) override; + void endSync() override; + void updatePathRenderNode() override; + + void setNode(QQuickPathItemNvprRenderNode *node); + + struct NvprPath { + QVector<GLubyte> cmd; + QVector<GLfloat> coord; + }; + +private: + void convertPath(const QQuickPath *path); + + QQuickPathItemNvprRenderNode *m_node = nullptr; + int m_dirty = 0; + + NvprPath m_path; + qreal m_strokeWidth; + QColor m_strokeColor; + QColor m_fillColor; + QQuickPathItem::JoinStyle m_joinStyle; + int m_miterLimit; + QQuickPathItem::CapStyle m_capStyle; + QQuickPathItem::FillRule m_fillRule; + bool m_dashActive; + qreal m_dashOffset; + QVector<qreal> m_dashPattern; + bool m_fillGradientActive; + QQuickPathItemGradientCache::GradientDesc m_fillGradient; +}; + +QDebug operator<<(QDebug debug, const QQuickPathItemNvprRenderer::NvprPath &path); + +class QQuickNvprMaterialManager +{ +public: + enum Material { + MatSolid, + MatLinearGradient, + + NMaterials + }; + + struct MaterialDesc { + GLuint ppl = 0; + GLuint prg = 0; + int uniLoc[4]; + }; + + void create(QQuickNvprFunctions *nvpr); + MaterialDesc *activateMaterial(Material m); + void releaseResources(); + +private: + QQuickNvprFunctions *m_nvpr; + MaterialDesc m_materials[NMaterials]; +}; + +class QQuickPathItemNvprRenderNode : public QSGRenderNode +{ +public: + QQuickPathItemNvprRenderNode(QQuickPathItem *item); + ~QQuickPathItemNvprRenderNode(); + + void render(const RenderState *state) override; + void releaseResources() override; + StateFlags changedStates() const override; + RenderingFlags flags() const override; + QRectF rect() const override; + + static bool isSupported(); + +private: + void updatePath(); + + static bool nvprInited; + static QQuickNvprFunctions nvpr; + static QQuickNvprMaterialManager mtlmgr; + + QQuickPathItem *m_item; + GLuint m_path = 0; + int m_dirty = 0; + + QQuickPathItemNvprRenderer::NvprPath m_source; + GLfloat m_strokeWidth; + QVector4D m_strokeColor; + QVector4D m_fillColor; + GLenum m_joinStyle; + GLint m_miterLimit; + GLenum m_capStyle; + GLenum m_fillRule; + GLfloat m_dashOffset; + QVector<GLfloat> m_dashPattern; + bool m_fillGradientActive; + QQuickPathItemGradientCache::GradientDesc m_fillGradient; + + friend class QQuickPathItemNvprRenderer; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_OPENGL + +#endif // QQUICKPATHITEMNVPRRENDERER_P_H diff --git a/src/quick/items/qquickpathitemsoftwarerenderer.cpp b/src/quick/items/qquickpathitemsoftwarerenderer.cpp new file mode 100644 index 0000000000..40732e4bf9 --- /dev/null +++ b/src/quick/items/qquickpathitemsoftwarerenderer.cpp @@ -0,0 +1,234 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickpathitemsoftwarerenderer_p.h" +#include <private/qquickpath_p_p.h> + +QT_BEGIN_NAMESPACE + +void QQuickPathItemSoftwareRenderer::beginSync() +{ + // nothing to do here +} + +void QQuickPathItemSoftwareRenderer::setPath(const QQuickPath *path) +{ + m_path = path ? path->path() : QPainterPath(); + m_dirty |= DirtyPath; +} + +void QQuickPathItemSoftwareRenderer::setStrokeColor(const QColor &color) +{ + m_pen.setColor(color); + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setStrokeWidth(qreal w) +{ + m_pen.setWidthF(w); + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setFillColor(const QColor &color) +{ + m_fillColor = color; + m_brush.setColor(m_fillColor); + m_dirty |= DirtyBrush; +} + +void QQuickPathItemSoftwareRenderer::setFillRule(QQuickPathItem::FillRule fillRule) +{ + m_fillRule = Qt::FillRule(fillRule); + m_dirty |= DirtyFillRule; +} + +void QQuickPathItemSoftwareRenderer::setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) +{ + m_pen.setJoinStyle(Qt::PenJoinStyle(joinStyle)); + m_pen.setMiterLimit(miterLimit); + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setCapStyle(QQuickPathItem::CapStyle capStyle) +{ + m_pen.setCapStyle(Qt::PenCapStyle(capStyle)); + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) +{ + switch (strokeStyle) { + case QQuickPathItem::SolidLine: + m_pen.setStyle(Qt::SolidLine); + break; + case QQuickPathItem::DashLine: + m_pen.setStyle(Qt::CustomDashLine); + m_pen.setDashPattern(dashPattern); + m_pen.setDashOffset(dashOffset); + break; + default: + break; + } + m_dirty |= DirtyPen; +} + +void QQuickPathItemSoftwareRenderer::setFillGradient(QQuickPathGradient *gradient) +{ + if (QQuickPathLinearGradient *linearGradient = qobject_cast<QQuickPathLinearGradient *>(gradient)) { + QLinearGradient painterGradient(linearGradient->x1(), linearGradient->y1(), + linearGradient->x2(), linearGradient->y2()); + painterGradient.setStops(linearGradient->sortedGradientStops()); + switch (gradient->spread()) { + case QQuickPathGradient::PadSpread: + painterGradient.setSpread(QGradient::PadSpread); + break; + case QQuickPathGradient::RepeatSpread: + painterGradient.setSpread(QGradient::RepeatSpread); + break; + case QQuickPathGradient::ReflectSpread: + painterGradient.setSpread(QGradient::ReflectSpread); + break; + default: + break; + } + m_brush = QBrush(painterGradient); + } else { + m_brush = QBrush(m_fillColor); + } + m_dirty |= DirtyBrush; +} + +void QQuickPathItemSoftwareRenderer::endSync() +{ + // nothing to do here +} + +void QQuickPathItemSoftwareRenderer::setNode(QQuickPathItemSoftwareRenderNode *node) +{ + if (m_node != node) { + m_node = node; + // Scenegraph nodes can be destroyed and then replaced by new ones over + // time; hence it is important to mark everything dirty for + // updatePathRenderNode(). We can assume the renderer has a full sync + // of the data at this point. + m_dirty = DirtyAll; + } +} + +void QQuickPathItemSoftwareRenderer::updatePathRenderNode() +{ + if (!m_dirty) + return; + + // updatePathRenderNode() can be called several times with different dirty + // state before render() gets invoked. So accumulate. + m_node->m_dirty |= m_dirty; + + if (m_dirty & DirtyPath) { + m_node->m_path = m_path; + m_node->m_path.setFillRule(m_fillRule); + } + + if (m_dirty & DirtyFillRule) + m_node->m_path.setFillRule(m_fillRule); + + if (m_dirty & DirtyPen) + m_node->m_pen = m_pen; + + if (m_dirty & DirtyBrush) + m_node->m_brush = m_brush; + + m_node->markDirty(QSGNode::DirtyMaterial); + m_dirty = 0; +} + +QQuickPathItemSoftwareRenderNode::QQuickPathItemSoftwareRenderNode(QQuickPathItem *item) + : m_item(item) +{ +} + +QQuickPathItemSoftwareRenderNode::~QQuickPathItemSoftwareRenderNode() +{ + releaseResources(); +} + +void QQuickPathItemSoftwareRenderNode::releaseResources() +{ +} + +void QQuickPathItemSoftwareRenderNode::render(const RenderState *state) +{ + if (m_path.isEmpty()) + return; + + QSGRendererInterface *rif = m_item->window()->rendererInterface(); + QPainter *p = static_cast<QPainter *>(rif->getResource(m_item->window(), QSGRendererInterface::PainterResource)); + Q_ASSERT(p); + + p->setTransform(matrix()->toTransform()); + p->setOpacity(inheritedOpacity()); + + const QRegion *clipRegion = state->clipRegion(); + if (clipRegion && !clipRegion->isEmpty()) + p->setClipRegion(*clipRegion, Qt::IntersectClip); + + p->setPen(!qFuzzyIsNull(m_pen.widthF()) && m_pen.color() != Qt::transparent ? m_pen : Qt::NoPen); + p->setBrush(m_brush.color() != Qt::transparent ? m_brush : Qt::NoBrush); + p->drawPath(m_path); + + m_dirty = 0; +} + +QSGRenderNode::StateFlags QQuickPathItemSoftwareRenderNode::changedStates() const +{ + return 0; +} + +QSGRenderNode::RenderingFlags QQuickPathItemSoftwareRenderNode::flags() const +{ + return BoundedRectRendering; // avoid fullscreen updates by saying we won't draw outside rect() +} + +QRectF QQuickPathItemSoftwareRenderNode::rect() const +{ + return QRect(0, 0, m_item->width(), m_item->height()); +} + +QT_END_NAMESPACE diff --git a/src/quick/items/qquickpathitemsoftwarerenderer_p.h b/src/quick/items/qquickpathitemsoftwarerenderer_p.h new file mode 100644 index 0000000000..584771425d --- /dev/null +++ b/src/quick/items/qquickpathitemsoftwarerenderer_p.h @@ -0,0 +1,127 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKPATHITEMSOFTWARERENDERER_P_H +#define QQUICKPATHITEMSOFTWARERENDERER_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qquickpathitem_p_p.h" +#include <qsgrendernode.h> +#include <QPen> +#include <QBrush> + +QT_BEGIN_NAMESPACE + +class QQuickPathItemSoftwareRenderNode; + +class QQuickPathItemSoftwareRenderer : public QQuickAbstractPathRenderer +{ +public: + enum Dirty { + DirtyPath = 0x01, + DirtyPen = 0x02, + DirtyFillRule = 0x04, + DirtyBrush = 0x08, + + DirtyAll = 0xFF + }; + + void beginSync() override; + void setPath(const QQuickPath *path) override; + void setStrokeColor(const QColor &color) override; + void setStrokeWidth(qreal w) override; + void setFillColor(const QColor &color) override; + void setFillRule(QQuickPathItem::FillRule fillRule) override; + void setJoinStyle(QQuickPathItem::JoinStyle joinStyle, int miterLimit) override; + void setCapStyle(QQuickPathItem::CapStyle capStyle) override; + void setStrokeStyle(QQuickPathItem::StrokeStyle strokeStyle, + qreal dashOffset, const QVector<qreal> &dashPattern) override; + void setFillGradient(QQuickPathGradient *gradient) override; + void endSync() override; + void updatePathRenderNode() override; + + void setNode(QQuickPathItemSoftwareRenderNode *node); + +private: + QQuickPathItemSoftwareRenderNode *m_node = nullptr; + int m_dirty = 0; + + QPainterPath m_path; + QPen m_pen; + QColor m_fillColor; + QBrush m_brush; + Qt::FillRule m_fillRule; +}; + +class QQuickPathItemSoftwareRenderNode : public QSGRenderNode +{ +public: + QQuickPathItemSoftwareRenderNode(QQuickPathItem *item); + ~QQuickPathItemSoftwareRenderNode(); + + void render(const RenderState *state) override; + void releaseResources() override; + StateFlags changedStates() const override; + RenderingFlags flags() const override; + QRectF rect() const override; + +private: + QQuickPathItem *m_item; + int m_dirty = 0; + + QPainterPath m_path; + QPen m_pen; + QBrush m_brush; + + friend class QQuickPathItemSoftwareRenderer; +}; + +QT_END_NAMESPACE + +#endif // QQUICKPATHITEMSOFTWARERENDERER_P_H diff --git a/src/quick/items/shaders/lineargradient.frag b/src/quick/items/shaders/lineargradient.frag new file mode 100644 index 0000000000..7f4a739109 --- /dev/null +++ b/src/quick/items/shaders/lineargradient.frag @@ -0,0 +1,9 @@ +uniform sampler2D gradTabTexture; +uniform highp float opacity; + +varying highp float gradTabIndex; + +void main() +{ + gl_FragColor = texture2D(gradTabTexture, vec2(gradTabIndex, 0.5)) * opacity; +} diff --git a/src/quick/items/shaders/lineargradient.vert b/src/quick/items/shaders/lineargradient.vert new file mode 100644 index 0000000000..eb21b8886b --- /dev/null +++ b/src/quick/items/shaders/lineargradient.vert @@ -0,0 +1,15 @@ +attribute vec4 vertexCoord; +attribute vec4 vertexColor; + +uniform mat4 matrix; +uniform vec2 gradStart; +uniform vec2 gradEnd; + +varying float gradTabIndex; + +void main() +{ + vec2 gradVec = gradEnd - gradStart; + gradTabIndex = dot(gradVec, vertexCoord.xy - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y); + gl_Position = matrix * vertexCoord; +} diff --git a/src/quick/items/shaders/lineargradient_core.frag b/src/quick/items/shaders/lineargradient_core.frag new file mode 100644 index 0000000000..5908acfa67 --- /dev/null +++ b/src/quick/items/shaders/lineargradient_core.frag @@ -0,0 +1,12 @@ +#version 150 core + +uniform sampler2D gradTabTexture; +uniform float opacity; + +in float gradTabIndex; +out vec4 fragColor; + +void main() +{ + fragColor = texture(gradTabTexture, vec2(gradTabIndex, 0.5)) * opacity; +} diff --git a/src/quick/items/shaders/lineargradient_core.vert b/src/quick/items/shaders/lineargradient_core.vert new file mode 100644 index 0000000000..60b56f38e3 --- /dev/null +++ b/src/quick/items/shaders/lineargradient_core.vert @@ -0,0 +1,17 @@ +#version 150 core + +in vec4 vertexCoord; +in vec4 vertexColor; + +uniform mat4 matrix; +uniform vec2 gradStart; +uniform vec2 gradEnd; + +out float gradTabIndex; + +void main() +{ + vec2 gradVec = gradEnd - gradStart; + gradTabIndex = dot(gradVec, vertexCoord.xy - gradStart) / (gradVec.x * gradVec.x + gradVec.y * gradVec.y); + gl_Position = matrix * vertexCoord; +} diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 8de205fc98..b8ed190b33 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -978,6 +978,10 @@ void Renderer::nodeChangedBatchRoot(Node *node, Node *root) e->root = root; e->boundsComputed = false; } + } else if (node->type() == QSGNode::RenderNodeType) { + RenderNodeElement *e = node->renderNodeElement(); + if (e) + e->root = root; } SHADOWNODE_TRAVERSE(node) diff --git a/src/quick/scenegraph/coreapi/qsgrendernode.cpp b/src/quick/scenegraph/coreapi/qsgrendernode.cpp index 5915d51f2b..1bc0210b72 100644 --- a/src/quick/scenegraph/coreapi/qsgrendernode.cpp +++ b/src/quick/scenegraph/coreapi/qsgrendernode.cpp @@ -160,10 +160,7 @@ QSGRenderNode::StateFlags QSGRenderNode::changedStates() const \list \li glDepthMask(false) \li glDisable(GL_DEPTH_TEST) - \li glStencilMask(0) - \li glEnable(GL_STENCIL_TEST)/glDisable(GL_STENCIL_TEST) depending on clip \li glStencilFunc(GL_EQUAL, state.stencilValue, 0xff) depending on clip - \li glEnable(GL_SCISSOR_TEST)/glDisable(GL_SCISSOR_TEST) depending on clip \li glScissor(state.scissorRect.x(), state.scissorRect.y(), state.scissorRect.width(), state.scissorRect.height()) depending on clip \li glEnable(GL_BLEND) diff --git a/src/quick/scenegraph/qsgdefaultrendercontext.cpp b/src/quick/scenegraph/qsgdefaultrendercontext.cpp index 2c5b4ff5c8..aaf4635c0c 100644 --- a/src/quick/scenegraph/qsgdefaultrendercontext.cpp +++ b/src/quick/scenegraph/qsgdefaultrendercontext.cpp @@ -260,7 +260,7 @@ void QSGDefaultRenderContext::compileShader(QSGMaterialShader *shader, QSGMateri if (vertexCode || fragmentCode) { Q_ASSERT_X((material->flags() & QSGMaterial::CustomCompileStep) == 0, "QSGRenderContext::compile()", - "materials with custom compile step cannot have custom vertex/fragment code"); + "materials with custom compile step cannot have modified vertex or fragment code"); QOpenGLShaderProgram *p = shader->program(); p->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexCode ? vertexCode : shader->vertexShader()); p->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragmentCode ? fragmentCode : shader->fragmentShader()); diff --git a/src/quick/scenegraph/util/qsgtexture.cpp b/src/quick/scenegraph/util/qsgtexture.cpp index 47248f2f37..d761eac62f 100644 --- a/src/quick/scenegraph/util/qsgtexture.cpp +++ b/src/quick/scenegraph/util/qsgtexture.cpp @@ -251,11 +251,15 @@ static void qt_debug_remove_texture(QSGTexture* texture) Specifies how the texture should treat texture coordinates. - \value Repeat Only the factional part of the texture coordiante is + \value Repeat Only the fractional part of the texture coordinate is used, causing values above 1 and below 0 to repeat. \value ClampToEdge Values above 1 are clamped to 1 and values below 0 are clamped to 0. + + \value MirroredRepeat When the texture coordinate is even, only the + fractional part is used. When odd, the texture coordinate is set to + \c{1 - fractional part}. This value has been introduced in Qt 5.10. */ /*! @@ -550,7 +554,9 @@ void QSGTexture::updateBindOptions(bool force) if (force || d->wrapChanged) { #ifndef QT_NO_DEBUG - if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat) { + if (d->horizontalWrap == Repeat || d->verticalWrap == Repeat + || d->horizontalWrap == MirroredRepeat || d->verticalWrap == MirroredRepeat) + { bool npotSupported = QOpenGLFunctions(QOpenGLContext::currentContext()).hasOpenGLFeature(QOpenGLFunctions::NPOTTextures); QSize size = textureSize(); bool isNpot = !isPowerOfTwo(size.width()) || !isPowerOfTwo(size.height()); @@ -558,8 +564,18 @@ void QSGTexture::updateBindOptions(bool force) qWarning("Scene Graph: This system does not support the REPEAT wrap mode for non-power-of-two textures."); } #endif - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, d->horizontalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); - funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, d->verticalWrap == Repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE); + GLenum wrapS = GL_CLAMP_TO_EDGE; + if (d->horizontalWrap == Repeat) + wrapS = GL_REPEAT; + else if (d->horizontalWrap == MirroredRepeat) + wrapS = GL_MIRRORED_REPEAT; + GLenum wrapT = GL_CLAMP_TO_EDGE; + if (d->verticalWrap == Repeat) + wrapT = GL_REPEAT; + else if (d->verticalWrap == MirroredRepeat) + wrapT = GL_MIRRORED_REPEAT; + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapS); + funcs->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT); d->wrapChanged = false; } #else diff --git a/src/quick/scenegraph/util/qsgtexture.h b/src/quick/scenegraph/util/qsgtexture.h index f0509b58ae..2b29525efd 100644 --- a/src/quick/scenegraph/util/qsgtexture.h +++ b/src/quick/scenegraph/util/qsgtexture.h @@ -58,7 +58,8 @@ public: enum WrapMode { Repeat, - ClampToEdge + ClampToEdge, + MirroredRepeat }; enum Filtering { diff --git a/src/quick/scenegraph/util/qsgtexture_p.h b/src/quick/scenegraph/util/qsgtexture_p.h index b6fcfc31c4..3a10d85b4d 100644 --- a/src/quick/scenegraph/util/qsgtexture_p.h +++ b/src/quick/scenegraph/util/qsgtexture_p.h @@ -70,8 +70,8 @@ public: uint wrapChanged : 1; uint filteringChanged : 1; - uint horizontalWrap : 1; - uint verticalWrap : 1; + uint horizontalWrap : 2; + uint verticalWrap : 2; uint mipmapMode : 2; uint filterMode : 2; }; diff --git a/src/quick/scenegraph/util/qsgtexturematerial.cpp b/src/quick/scenegraph/util/qsgtexturematerial.cpp index 9326ea640d..fcafbba6a2 100644 --- a/src/quick/scenegraph/util/qsgtexturematerial.cpp +++ b/src/quick/scenegraph/util/qsgtexturematerial.cpp @@ -278,7 +278,7 @@ void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture) Returns this material's horizontal wrap mode. - The default horizontal wrap mode is \c QSGTexutre::ClampToEdge. + The default horizontal wrap mode is \c QSGTexture::ClampToEdge. */ @@ -299,7 +299,7 @@ void QSGOpaqueTextureMaterial::setTexture(QSGTexture *texture) Returns this material's vertical wrap mode. - The default vertical wrap mode is \c QSGTexutre::ClampToEdge. + The default vertical wrap mode is \c QSGTexture::ClampToEdge. */ diff --git a/src/quick/util/qquicknvprfunctions.cpp b/src/quick/util/qquicknvprfunctions.cpp new file mode 100644 index 0000000000..40eb2bb932 --- /dev/null +++ b/src/quick/util/qquicknvprfunctions.cpp @@ -0,0 +1,284 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquicknvprfunctions_p.h" + +#ifndef QT_NO_OPENGL + +#include <QOpenGLContext> +#include <QOffscreenSurface> +#include <QOpenGLExtraFunctions> +#include "qquicknvprfunctions_p_p.h" + +QT_BEGIN_NAMESPACE + +/*! + \class QQuickNvprFunctions + + \brief Function resolvers and other helpers for GL_NV_path_rendering + for both desktop (GL 4.3+) and mobile/embedded (GLES 3.1+) in a manner + that does not distract builds that do not have NVPR support either at + compile or run time. + + \internal + */ + +QQuickNvprFunctions::QQuickNvprFunctions() + : d(new QQuickNvprFunctionsPrivate(this)) +{ +} + +QQuickNvprFunctions::~QQuickNvprFunctions() +{ + delete d; +} + +/*! + \return a recommended QSurfaceFormat suitable for GL_NV_path_rendering on top + of OpenGL 4.3 or OpenGL ES 3.1. + */ +QSurfaceFormat QQuickNvprFunctions::format() +{ + QSurfaceFormat fmt; + fmt.setDepthBufferSize(24); + fmt.setStencilBufferSize(8); + if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { + fmt.setVersion(4, 3); + fmt.setProfile(QSurfaceFormat::CompatibilityProfile); + } else if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGLES) { + fmt.setVersion(3, 1); + } + return fmt; +} + +/*! + \return true if GL_NV_path_rendering is supported with the current OpenGL + context. + + When there is no current context, a temporary dummy one will be created and + made current. + */ +bool QQuickNvprFunctions::isSupported() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QScopedPointer<QOpenGLContext> tempContext; + QScopedPointer<QOffscreenSurface> tempSurface; + if (!ctx) { + tempContext.reset(new QOpenGLContext); + if (!tempContext->create()) + return false; + ctx = tempContext.data(); + tempSurface.reset(new QOffscreenSurface); + tempSurface->setFormat(ctx->format()); + tempSurface->create(); + if (!ctx->makeCurrent(tempSurface.data())) + return false; + } + + if (!ctx->hasExtension(QByteArrayLiteral("GL_NV_path_rendering"))) + return false; + + // Do not check for DSA as the string may not be exposed on ES + // drivers, yet the functions we need are resolvable. +#if 0 + if (!ctx->hasExtension(QByteArrayLiteral("GL_EXT_direct_state_access"))) { + qWarning("QtQuickPath/NVPR: GL_EXT_direct_state_access not supported"); + return false; + } +#endif + + return true; +} + +/*! + Initializes using the current OpenGL context. + + \return true when GL_NV_path_rendering is supported and initialization was + successful. + */ +bool QQuickNvprFunctions::create() +{ + return isSupported() && d->resolve(); +} + +/*! + Creates a program pipeline consisting of a separable fragment shader program. + + This is essential for using NVPR with OpenGL ES 3.1+ since normal, + GLES2-style programs would not work without a vertex shader. + + \note \a fragmentShaderSource should be a \c{version 310 es} shader since + this works both on desktop and embedded NVIDIA drivers, thus avoiding the + need to fight GLSL and GLSL ES differences. + + The pipeline object is stored into \a pipeline, the fragment shader program + into \a program. + + Use QOpenGLExtraFunctions to set uniforms, bind the pipeline, etc. + + \return \c false on failure in which case the error log is printed on the + debug output. \c true on success. + */ +bool QQuickNvprFunctions::createFragmentOnlyPipeline(const char *fragmentShaderSource, GLuint *pipeline, GLuint *program) +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + if (!ctx) + return false; + + QOpenGLExtraFunctions *f = ctx->extraFunctions(); + *program = f->glCreateShaderProgramv(GL_FRAGMENT_SHADER, 1, &fragmentShaderSource); + GLint status = 0; + f->glGetProgramiv(*program, GL_LINK_STATUS, &status); + if (!status) { + GLint len = 0; + f->glGetProgramiv(*program, GL_INFO_LOG_LENGTH, &len); + if (len) { + QByteArray s; + s.resize(len); + f->glGetProgramInfoLog(*program, s.count(), nullptr, s.data()); + qWarning("Failed to create separable shader program:\n%s", s.constData()); + } + return false; + } + + f->glGenProgramPipelines(1, pipeline); + f->glUseProgramStages(*pipeline, GL_FRAGMENT_SHADER_BIT, *program); + f->glActiveShaderProgram(*pipeline, *program); + + f->glValidateProgramPipeline(*pipeline); + status = 0; + f->glGetProgramPipelineiv(*pipeline, GL_VALIDATE_STATUS, &status); + if (!status) { + GLint len = 0; + f->glGetProgramPipelineiv(*pipeline, GL_INFO_LOG_LENGTH, &len); + if (len) { + QByteArray s; + s.resize(len); + f->glGetProgramPipelineInfoLog(*pipeline, s.count(), nullptr, s.data()); + qWarning("Program pipeline validation failed:\n%s", s.constData()); + } + return false; + } + + return true; +} + +#define PROC(type, name) reinterpret_cast<type>(ctx->getProcAddress(#name)) + +bool QQuickNvprFunctionsPrivate::resolve() +{ + QOpenGLContext *ctx = QOpenGLContext::currentContext(); + + q->genPaths = PROC(PFNGLGENPATHSNVPROC, glGenPathsNV); + q->deletePaths = PROC(PFNGLDELETEPATHSNVPROC, glDeletePathsNV); + q->isPath = PROC(PFNGLISPATHNVPROC, glIsPathNV); + q->pathCommands = PROC(PFNGLPATHCOMMANDSNVPROC, glPathCommandsNV); + q->pathCoords = PROC(PFNGLPATHCOORDSNVPROC, glPathCoordsNV); + q->pathSubCommands = PROC(PFNGLPATHSUBCOMMANDSNVPROC, glPathSubCommandsNV); + q->pathSubCoords = PROC(PFNGLPATHSUBCOORDSNVPROC, glPathSubCoordsNV); + q->pathString = PROC(PFNGLPATHSTRINGNVPROC, glPathStringNV); + q->pathGlyphs = PROC(PFNGLPATHGLYPHSNVPROC, glPathGlyphsNV); + q->pathGlyphRange = PROC(PFNGLPATHGLYPHRANGENVPROC, glPathGlyphRangeNV); + q->weightPaths = PROC(PFNGLWEIGHTPATHSNVPROC, glWeightPathsNV); + q->copyPath = PROC(PFNGLCOPYPATHNVPROC, glCopyPathNV); + q->interpolatePaths = PROC(PFNGLINTERPOLATEPATHSNVPROC, glInterpolatePathsNV); + q->transformPath = PROC(PFNGLTRANSFORMPATHNVPROC, glTransformPathNV); + q->pathParameteriv = PROC(PFNGLPATHPARAMETERIVNVPROC, glPathParameterivNV); + q->pathParameteri = PROC(PFNGLPATHPARAMETERINVPROC, glPathParameteriNV); + q->pathParameterfv = PROC(PFNGLPATHPARAMETERFVNVPROC, glPathParameterfvNV); + q->pathParameterf = PROC(PFNGLPATHPARAMETERFNVPROC, glPathParameterfNV); + q->pathDashArray = PROC(PFNGLPATHDASHARRAYNVPROC, glPathDashArrayNV); + q->pathStencilFunc = PROC(PFNGLPATHSTENCILFUNCNVPROC, glPathStencilFuncNV); + q->pathStencilDepthOffset = PROC(PFNGLPATHSTENCILDEPTHOFFSETNVPROC, glPathStencilDepthOffsetNV); + q->stencilFillPath = PROC(PFNGLSTENCILFILLPATHNVPROC, glStencilFillPathNV); + q->stencilStrokePath = PROC(PFNGLSTENCILSTROKEPATHNVPROC, glStencilStrokePathNV); + q->stencilFillPathInstanced = PROC(PFNGLSTENCILFILLPATHINSTANCEDNVPROC, glStencilFillPathInstancedNV); + q->stencilStrokePathInstanced = PROC(PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC, glStencilStrokePathInstancedNV); + q->pathCoverDepthFunc = PROC(PFNGLPATHCOVERDEPTHFUNCNVPROC, glPathCoverDepthFuncNV); + q->pathColorGen = PROC(PFNGLPATHCOLORGENNVPROC, glPathColorGenNV); + q->pathTexGen = PROC(PFNGLPATHTEXGENNVPROC, glPathTexGenNV); + q->pathFogGen = PROC(PFNGLPATHFOGGENNVPROC, glPathFogGenNV); + q->coverFillPath = PROC(PFNGLCOVERFILLPATHNVPROC, glCoverFillPathNV); + q->coverStrokePath = PROC(PFNGLCOVERSTROKEPATHNVPROC, glCoverStrokePathNV); + q->coverFillPathInstanced = PROC(PFNGLCOVERFILLPATHINSTANCEDNVPROC, glCoverFillPathInstancedNV); + q->coverStrokePathInstanced = PROC(PFNGLCOVERSTROKEPATHINSTANCEDNVPROC, glCoverStrokePathInstancedNV); + q->getPathParameteriv = PROC(PFNGLGETPATHPARAMETERIVNVPROC, glGetPathParameterivNV); + q->getPathParameterfv = PROC(PFNGLGETPATHPARAMETERFVNVPROC, glGetPathParameterfvNV); + q->getPathCommands = PROC(PFNGLGETPATHCOMMANDSNVPROC, glGetPathCommandsNV); + q->getPathCoords = PROC(PFNGLGETPATHCOORDSNVPROC, glGetPathCoordsNV); + q->getPathDashArray = PROC(PFNGLGETPATHDASHARRAYNVPROC, glGetPathDashArrayNV); + q->getPathMetrics = PROC(PFNGLGETPATHMETRICSNVPROC, glGetPathMetricsNV); + q->getPathMetricRange = PROC(PFNGLGETPATHMETRICRANGENVPROC, glGetPathMetricRangeNV); + q->getPathSpacing = PROC(PFNGLGETPATHSPACINGNVPROC, glGetPathSpacingNV); + q->getPathColorgeniv = PROC(PFNGLGETPATHCOLORGENIVNVPROC, glGetPathColorGenivNV); + q->getPathColorgenfv = PROC(PFNGLGETPATHCOLORGENFVNVPROC, glGetPathColorGenfvNV); + q->getPathTexGeniv = PROC(PFNGLGETPATHTEXGENIVNVPROC, glGetPathTexGenivNV); + q->getPathTexGenfv = PROC(PFNGLGETPATHTEXGENFVNVPROC, glGetPathTexGenfvNV); + q->isPointInFillPath = PROC(PFNGLISPOINTINFILLPATHNVPROC, glIsPointInFillPathNV); + q->isPointInStrokePath = PROC(PFNGLISPOINTINSTROKEPATHNVPROC, glIsPointInStrokePathNV); + q->getPathLength = PROC(PFNGLGETPATHLENGTHNVPROC, glGetPathLengthNV); + q->getPointAlongPath = PROC(PFNGLPOINTALONGPATHNVPROC, glPointAlongPathNV); + q->matrixLoad3x2f = PROC(PFNGLMATRIXLOAD3X2FNVPROC, glMatrixLoad3x2fNV); + q->matrixLoad3x3f = PROC(PFNGLMATRIXLOAD3X3FNVPROC, glMatrixLoad3x3fNV); + q->matrixLoadTranspose3x3f = PROC(PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC, glMatrixLoadTranspose3x3fNV); + q->matrixMult3x2f = PROC(PFNGLMATRIXMULT3X2FNVPROC, glMatrixMult3x2fNV); + q->matrixMult3x3f = PROC(PFNGLMATRIXMULT3X3FNVPROC, glMatrixMult3x3fNV); + q->matrixMultTranspose3x3f = PROC(PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC, glMatrixMultTranspose3x3fNV); + q->stencilThenCoverFillPath = PROC(PFNGLSTENCILTHENCOVERFILLPATHNVPROC, glStencilThenCoverFillPathNV); + q->stencilThenCoverStrokePath = PROC(PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC, glStencilThenCoverStrokePathNV); + q->stencilThenCoverFillPathInstanced = PROC(PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC, glStencilThenCoverFillPathInstancedNV); + q->stencilThenCoverStrokePathInstanced = PROC(PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC, glStencilThenCoverStrokePathInstancedNV); + q->pathGlyphIndexRange = PROC(PFNGLPATHGLYPHINDEXRANGENVPROC, glPathGlyphIndexRangeNV); + q->pathGlyphIndexArray = PROC(PFNGLPATHGLYPHINDEXARRAYNVPROC, glPathGlyphIndexArrayNV); + q->pathMemoryGlyphIndexArray = PROC(PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC, glPathMemoryGlyphIndexArrayNV); + q->programPathFragmentInputGen = PROC(PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC, glProgramPathFragmentInputGenNV); + q->getProgramResourcefv = PROC(PFNGLGETPROGRAMRESOURCEFVNVPROC, glGetProgramResourcefvNV); + + q->matrixLoadf = PROC(PFNGLMATRIXLOADFEXTPROC, glMatrixLoadfEXT); + q->matrixLoadIdentity = PROC(PFNGLMATRIXLOADIDENTITYEXTPROC, glMatrixLoadIdentityEXT); + + return q->genPaths != nullptr // base path rendering ext + && q->programPathFragmentInputGen != nullptr // updated path rendering ext + && q->matrixLoadf != nullptr // direct state access ext + && q->matrixLoadIdentity != nullptr; +} + +QT_END_NAMESPACE + +#endif // QT_NO_OPENGL diff --git a/src/quick/util/qquicknvprfunctions_p.h b/src/quick/util/qquicknvprfunctions_p.h new file mode 100644 index 0000000000..7900388305 --- /dev/null +++ b/src/quick/util/qquicknvprfunctions_p.h @@ -0,0 +1,406 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKNVPRFUNCTIONS_P_H +#define QQUICKNVPRFUNCTIONS_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include <qopengl.h> +#include <QtGui/qsurfaceformat.h> + +#ifndef QT_NO_OPENGL + +QT_BEGIN_NAMESPACE + +#ifndef GL_NV_path_rendering +#define GL_PATH_FORMAT_SVG_NV 0x9070 +#define GL_PATH_FORMAT_PS_NV 0x9071 +#define GL_STANDARD_FONT_NAME_NV 0x9072 +#define GL_SYSTEM_FONT_NAME_NV 0x9073 +#define GL_FILE_NAME_NV 0x9074 +#define GL_PATH_STROKE_WIDTH_NV 0x9075 +#define GL_PATH_END_CAPS_NV 0x9076 +#define GL_PATH_INITIAL_END_CAP_NV 0x9077 +#define GL_PATH_TERMINAL_END_CAP_NV 0x9078 +#define GL_PATH_JOIN_STYLE_NV 0x9079 +#define GL_PATH_MITER_LIMIT_NV 0x907A +#define GL_PATH_DASH_CAPS_NV 0x907B +#define GL_PATH_INITIAL_DASH_CAP_NV 0x907C +#define GL_PATH_TERMINAL_DASH_CAP_NV 0x907D +#define GL_PATH_DASH_OFFSET_NV 0x907E +#define GL_PATH_CLIENT_LENGTH_NV 0x907F +#define GL_PATH_FILL_MODE_NV 0x9080 +#define GL_PATH_FILL_MASK_NV 0x9081 +#define GL_PATH_FILL_COVER_MODE_NV 0x9082 +#define GL_PATH_STROKE_COVER_MODE_NV 0x9083 +#define GL_PATH_STROKE_MASK_NV 0x9084 +#define GL_COUNT_UP_NV 0x9088 +#define GL_COUNT_DOWN_NV 0x9089 +#define GL_PATH_OBJECT_BOUNDING_BOX_NV 0x908A +#define GL_CONVEX_HULL_NV 0x908B +#define GL_BOUNDING_BOX_NV 0x908D +#define GL_TRANSLATE_X_NV 0x908E +#define GL_TRANSLATE_Y_NV 0x908F +#define GL_TRANSLATE_2D_NV 0x9090 +#define GL_TRANSLATE_3D_NV 0x9091 +#define GL_AFFINE_2D_NV 0x9092 +#define GL_AFFINE_3D_NV 0x9094 +#define GL_TRANSPOSE_AFFINE_2D_NV 0x9096 +#define GL_TRANSPOSE_AFFINE_3D_NV 0x9098 +#define GL_UTF8_NV 0x909A +#define GL_UTF16_NV 0x909B +#define GL_BOUNDING_BOX_OF_BOUNDING_BOXES_NV 0x909C +#define GL_PATH_COMMAND_COUNT_NV 0x909D +#define GL_PATH_COORD_COUNT_NV 0x909E +#define GL_PATH_DASH_ARRAY_COUNT_NV 0x909F +#define GL_PATH_COMPUTED_LENGTH_NV 0x90A0 +#define GL_PATH_FILL_BOUNDING_BOX_NV 0x90A1 +#define GL_PATH_STROKE_BOUNDING_BOX_NV 0x90A2 +#define GL_SQUARE_NV 0x90A3 +#define GL_ROUND_NV 0x90A4 +#define GL_TRIANGULAR_NV 0x90A5 +#define GL_BEVEL_NV 0x90A6 +#define GL_MITER_REVERT_NV 0x90A7 +#define GL_MITER_TRUNCATE_NV 0x90A8 +#define GL_SKIP_MISSING_GLYPH_NV 0x90A9 +#define GL_USE_MISSING_GLYPH_NV 0x90AA +#define GL_PATH_ERROR_POSITION_NV 0x90AB +#define GL_PATH_FOG_GEN_MODE_NV 0x90AC +#define GL_ACCUM_ADJACENT_PAIRS_NV 0x90AD +#define GL_ADJACENT_PAIRS_NV 0x90AE +#define GL_FIRST_TO_REST_NV 0x90AF +#define GL_PATH_GEN_MODE_NV 0x90B0 +#define GL_PATH_GEN_COEFF_NV 0x90B1 +#define GL_PATH_GEN_COLOR_FORMAT_NV 0x90B2 +#define GL_PATH_GEN_COMPONENTS_NV 0x90B3 +#define GL_PATH_STENCIL_FUNC_NV 0x90B7 +#define GL_PATH_STENCIL_REF_NV 0x90B8 +#define GL_PATH_STENCIL_VALUE_MASK_NV 0x90B9 +#define GL_PATH_STENCIL_DEPTH_OFFSET_FACTOR_NV 0x90BD +#define GL_PATH_STENCIL_DEPTH_OFFSET_UNITS_NV 0x90BE +#define GL_PATH_COVER_DEPTH_FUNC_NV 0x90BF +#define GL_PATH_DASH_OFFSET_RESET_NV 0x90B4 +#define GL_MOVE_TO_RESETS_NV 0x90B5 +#define GL_MOVE_TO_CONTINUES_NV 0x90B6 +#define GL_CLOSE_PATH_NV 0x00 +#define GL_MOVE_TO_NV 0x02 +#define GL_RELATIVE_MOVE_TO_NV 0x03 +#define GL_LINE_TO_NV 0x04 +#define GL_RELATIVE_LINE_TO_NV 0x05 +#define GL_HORIZONTAL_LINE_TO_NV 0x06 +#define GL_RELATIVE_HORIZONTAL_LINE_TO_NV 0x07 +#define GL_VERTICAL_LINE_TO_NV 0x08 +#define GL_RELATIVE_VERTICAL_LINE_TO_NV 0x09 +#define GL_QUADRATIC_CURVE_TO_NV 0x0A +#define GL_RELATIVE_QUADRATIC_CURVE_TO_NV 0x0B +#define GL_CUBIC_CURVE_TO_NV 0x0C +#define GL_RELATIVE_CUBIC_CURVE_TO_NV 0x0D +#define GL_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0E +#define GL_RELATIVE_SMOOTH_QUADRATIC_CURVE_TO_NV 0x0F +#define GL_SMOOTH_CUBIC_CURVE_TO_NV 0x10 +#define GL_RELATIVE_SMOOTH_CUBIC_CURVE_TO_NV 0x11 +#define GL_SMALL_CCW_ARC_TO_NV 0x12 +#define GL_RELATIVE_SMALL_CCW_ARC_TO_NV 0x13 +#define GL_SMALL_CW_ARC_TO_NV 0x14 +#define GL_RELATIVE_SMALL_CW_ARC_TO_NV 0x15 +#define GL_LARGE_CCW_ARC_TO_NV 0x16 +#define GL_RELATIVE_LARGE_CCW_ARC_TO_NV 0x17 +#define GL_LARGE_CW_ARC_TO_NV 0x18 +#define GL_RELATIVE_LARGE_CW_ARC_TO_NV 0x19 +#define GL_RESTART_PATH_NV 0xF0 +#define GL_DUP_FIRST_CUBIC_CURVE_TO_NV 0xF2 +#define GL_DUP_LAST_CUBIC_CURVE_TO_NV 0xF4 +#define GL_RECT_NV 0xF6 +#define GL_CIRCULAR_CCW_ARC_TO_NV 0xF8 +#define GL_CIRCULAR_CW_ARC_TO_NV 0xFA +#define GL_CIRCULAR_TANGENT_ARC_TO_NV 0xFC +#define GL_ARC_TO_NV 0xFE +#define GL_RELATIVE_ARC_TO_NV 0xFF +#define GL_BOLD_BIT_NV 0x01 +#define GL_ITALIC_BIT_NV 0x02 +#define GL_GLYPH_WIDTH_BIT_NV 0x01 +#define GL_GLYPH_HEIGHT_BIT_NV 0x02 +#define GL_GLYPH_HORIZONTAL_BEARING_X_BIT_NV 0x04 +#define GL_GLYPH_HORIZONTAL_BEARING_Y_BIT_NV 0x08 +#define GL_GLYPH_HORIZONTAL_BEARING_ADVANCE_BIT_NV 0x10 +#define GL_GLYPH_VERTICAL_BEARING_X_BIT_NV 0x20 +#define GL_GLYPH_VERTICAL_BEARING_Y_BIT_NV 0x40 +#define GL_GLYPH_VERTICAL_BEARING_ADVANCE_BIT_NV 0x80 +#define GL_GLYPH_HAS_KERNING_BIT_NV 0x100 +#define GL_FONT_X_MIN_BOUNDS_BIT_NV 0x00010000 +#define GL_FONT_Y_MIN_BOUNDS_BIT_NV 0x00020000 +#define GL_FONT_X_MAX_BOUNDS_BIT_NV 0x00040000 +#define GL_FONT_Y_MAX_BOUNDS_BIT_NV 0x00080000 +#define GL_FONT_UNITS_PER_EM_BIT_NV 0x00100000 +#define GL_FONT_ASCENDER_BIT_NV 0x00200000 +#define GL_FONT_DESCENDER_BIT_NV 0x00400000 +#define GL_FONT_HEIGHT_BIT_NV 0x00800000 +#define GL_FONT_MAX_ADVANCE_WIDTH_BIT_NV 0x01000000 +#define GL_FONT_MAX_ADVANCE_HEIGHT_BIT_NV 0x02000000 +#define GL_FONT_UNDERLINE_POSITION_BIT_NV 0x04000000 +#define GL_FONT_UNDERLINE_THICKNESS_BIT_NV 0x08000000 +#define GL_FONT_HAS_KERNING_BIT_NV 0x10000000 +#define GL_PRIMARY_COLOR_NV 0x852C +#define GL_SECONDARY_COLOR_NV 0x852D +#define GL_ROUNDED_RECT_NV 0xE8 +#define GL_RELATIVE_ROUNDED_RECT_NV 0xE9 +#define GL_ROUNDED_RECT2_NV 0xEA +#define GL_RELATIVE_ROUNDED_RECT2_NV 0xEB +#define GL_ROUNDED_RECT4_NV 0xEC +#define GL_RELATIVE_ROUNDED_RECT4_NV 0xED +#define GL_ROUNDED_RECT8_NV 0xEE +#define GL_RELATIVE_ROUNDED_RECT8_NV 0xEF +#define GL_RELATIVE_RECT_NV 0xF7 +#define GL_FONT_GLYPHS_AVAILABLE_NV 0x9368 +#define GL_FONT_TARGET_UNAVAILABLE_NV 0x9369 +#define GL_FONT_UNAVAILABLE_NV 0x936A +#define GL_FONT_UNINTELLIGIBLE_NV 0x936B +#define GL_CONIC_CURVE_TO_NV 0x1A +#define GL_RELATIVE_CONIC_CURVE_TO_NV 0x1B +#define GL_FONT_NUM_GLYPH_INDICES_BIT_NV 0x20000000 +#define GL_STANDARD_FONT_FORMAT_NV 0x936C +#define GL_2_BYTES_NV 0x1407 +#define GL_3_BYTES_NV 0x1408 +#define GL_4_BYTES_NV 0x1409 +#define GL_EYE_LINEAR_NV 0x2400 +#define GL_OBJECT_LINEAR_NV 0x2401 +#define GL_CONSTANT_NV 0x8576 +#define GL_PATH_PROJECTION_NV 0x1701 +#define GL_PATH_MODELVIEW_NV 0x1700 +#define GL_PATH_MODELVIEW_STACK_DEPTH_NV 0x0BA3 +#define GL_PATH_MODELVIEW_MATRIX_NV 0x0BA6 +#define GL_PATH_MAX_MODELVIEW_STACK_DEPTH_NV 0x0D36 +#define GL_PATH_TRANSPOSE_MODELVIEW_MATRIX_NV 0x84E3 +#define GL_PATH_PROJECTION_STACK_DEPTH_NV 0x0BA4 +#define GL_PATH_PROJECTION_MATRIX_NV 0x0BA7 +#define GL_PATH_MAX_PROJECTION_STACK_DEPTH_NV 0x0D38 +#define GL_PATH_TRANSPOSE_PROJECTION_MATRIX_NV 0x84E4 +#define GL_FRAGMENT_INPUT_NV 0x936D + +typedef GLuint (QOPENGLF_APIENTRYP PFNGLGENPATHSNVPROC) (GLsizei range); +typedef void (QOPENGLF_APIENTRYP PFNGLDELETEPATHSNVPROC) (GLuint path, GLsizei range); +typedef GLboolean (QOPENGLF_APIENTRYP PFNGLISPATHNVPROC) (GLuint path); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOMMANDSNVPROC) (GLuint path, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOORDSNVPROC) (GLuint path, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSUBCOMMANDSNVPROC) (GLuint path, GLsizei commandStart, GLsizei commandsToDelete, GLsizei numCommands, const GLubyte *commands, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSUBCOORDSNVPROC) (GLuint path, GLsizei coordStart, GLsizei numCoords, GLenum coordType, const void *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSTRINGNVPROC) (GLuint path, GLenum format, GLsizei length, const void *pathString); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHGLYPHSNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLsizei numGlyphs, GLenum type, const void *charcodes, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHGLYPHRANGENVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyph, GLsizei numGlyphs, GLenum handleMissingGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (QOPENGLF_APIENTRYP PFNGLWEIGHTPATHSNVPROC) (GLuint resultPath, GLsizei numPaths, const GLuint *paths, const GLfloat *weights); +typedef void (QOPENGLF_APIENTRYP PFNGLCOPYPATHNVPROC) (GLuint resultPath, GLuint srcPath); +typedef void (QOPENGLF_APIENTRYP PFNGLINTERPOLATEPATHSNVPROC) (GLuint resultPath, GLuint pathA, GLuint pathB, GLfloat weight); +typedef void (QOPENGLF_APIENTRYP PFNGLTRANSFORMPATHNVPROC) (GLuint resultPath, GLuint srcPath, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, const GLint *value); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERINVPROC) (GLuint path, GLenum pname, GLint value); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, const GLfloat *value); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHPARAMETERFNVPROC) (GLuint path, GLenum pname, GLfloat value); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHDASHARRAYNVPROC) (GLuint path, GLsizei dashCount, const GLfloat *dashArray); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSTENCILFUNCNVPROC) (GLenum func, GLint ref, GLuint mask); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHSTENCILDEPTHOFFSETNVPROC) (GLfloat factor, GLfloat units); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOVERDEPTHFUNCNVPROC) (GLenum func); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHCOLORGENNVPROC) (GLenum color, GLenum genMode, GLenum colorFormat, const GLfloat *coeffs); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHTEXGENNVPROC) (GLenum texCoordSet, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (QOPENGLF_APIENTRYP PFNGLPATHFOGGENNVPROC) (GLenum genMode); +typedef void (QOPENGLF_APIENTRYP PFNGLCOVERFILLPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (QOPENGLF_APIENTRYP PFNGLCOVERSTROKEPATHNVPROC) (GLuint path, GLenum coverMode); +typedef void (QOPENGLF_APIENTRYP PFNGLCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHPARAMETERIVNVPROC) (GLuint path, GLenum pname, GLint *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHPARAMETERFVNVPROC) (GLuint path, GLenum pname, GLfloat *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOMMANDSNVPROC) (GLuint path, GLubyte *commands); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOORDSNVPROC) (GLuint path, GLfloat *coords); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHDASHARRAYNVPROC) (GLuint path, GLfloat *dashArray); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHMETRICSNVPROC) (GLbitfield metricQueryMask, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLsizei stride, GLfloat *metrics); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHMETRICRANGENVPROC) (GLbitfield metricQueryMask, GLuint firstPathName, GLsizei numPaths, GLsizei stride, GLfloat *metrics); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHSPACINGNVPROC) (GLenum pathListMode, GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLfloat advanceScale, GLfloat kerningScale, GLenum transformType, GLfloat *returnedSpacing); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOLORGENIVNVPROC) (GLenum color, GLenum pname, GLint *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHCOLORGENFVNVPROC) (GLenum color, GLenum pname, GLfloat *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHTEXGENIVNVPROC) (GLenum texCoordSet, GLenum pname, GLint *value); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPATHTEXGENFVNVPROC) (GLenum texCoordSet, GLenum pname, GLfloat *value); +typedef GLboolean (QOPENGLF_APIENTRYP PFNGLISPOINTINFILLPATHNVPROC) (GLuint path, GLuint mask, GLfloat x, GLfloat y); +typedef GLboolean (QOPENGLF_APIENTRYP PFNGLISPOINTINSTROKEPATHNVPROC) (GLuint path, GLfloat x, GLfloat y); +typedef GLfloat (QOPENGLF_APIENTRYP PFNGLGETPATHLENGTHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments); +typedef GLboolean (QOPENGLF_APIENTRYP PFNGLPOINTALONGPATHNVPROC) (GLuint path, GLsizei startSegment, GLsizei numSegments, GLfloat distance, GLfloat *x, GLfloat *y, GLfloat *tangentX, GLfloat *tangentY); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOAD3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOAD3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXMULT3X2FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXMULT3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC) (GLenum matrixMode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHNVPROC) (GLuint path, GLenum fillMode, GLuint mask, GLenum coverMode); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC) (GLuint path, GLint reference, GLuint mask, GLenum coverMode); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLenum fillMode, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef void (QOPENGLF_APIENTRYP PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC) (GLsizei numPaths, GLenum pathNameType, const void *paths, GLuint pathBase, GLint reference, GLuint mask, GLenum coverMode, GLenum transformType, const GLfloat *transformValues); +typedef GLenum (QOPENGLF_APIENTRYP PFNGLPATHGLYPHINDEXRANGENVPROC) (GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint pathParameterTemplate, GLfloat emScale, GLuint baseAndCount[2]); +typedef GLenum (QOPENGLF_APIENTRYP PFNGLPATHGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, const void *fontName, GLbitfield fontStyle, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef GLenum (QOPENGLF_APIENTRYP PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC) (GLuint firstPathName, GLenum fontTarget, GLsizeiptr fontSize, const void *fontData, GLsizei faceIndex, GLuint firstGlyphIndex, GLsizei numGlyphs, GLuint pathParameterTemplate, GLfloat emScale); +typedef void (QOPENGLF_APIENTRYP PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC) (GLuint program, GLint location, GLenum genMode, GLint components, const GLfloat *coeffs); +typedef void (QOPENGLF_APIENTRYP PFNGLGETPROGRAMRESOURCEFVNVPROC) (GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum *props, GLsizei bufSize, GLsizei *length, GLfloat *params); +#endif + +#ifndef GL_FLAT +#define GL_FLAT 0x1D00 +#endif + +#ifndef GL_INVERT +#define GL_INVERT 0x150A +#endif + +#ifndef GL_EXT_direct_state_access +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOADFEXTPROC) (GLenum mode, const GLfloat *m); +typedef void (QOPENGLF_APIENTRYP PFNGLMATRIXLOADIDENTITYEXTPROC) (GLenum mode); +#endif + +// When building on a system with GLES 2.0 or 3.0, we may still compile the NVPR +// code path even though it's never used. Keep it compiling by defining the +// necessary ES 3.1 separable program constants. +#ifndef GL_FRAGMENT_SHADER_BIT +#define GL_FRAGMENT_SHADER_BIT 0x00000002 +#endif +#ifndef GL_UNIFORM +#define GL_UNIFORM 0x92E1 +#endif + +class QQuickNvprFunctionsPrivate; + +class QQuickNvprFunctions +{ +public: + QQuickNvprFunctions(); + ~QQuickNvprFunctions(); + + static QSurfaceFormat format(); + static bool isSupported(); + + bool create(); + + bool createFragmentOnlyPipeline(const char *fragmentShaderSource, GLuint *pipeline, GLuint *program); + + PFNGLGENPATHSNVPROC genPaths = nullptr; + PFNGLDELETEPATHSNVPROC deletePaths = nullptr; + PFNGLISPATHNVPROC isPath = nullptr; + PFNGLPATHCOMMANDSNVPROC pathCommands = nullptr; + PFNGLPATHCOORDSNVPROC pathCoords = nullptr; + PFNGLPATHSUBCOMMANDSNVPROC pathSubCommands = nullptr; + PFNGLPATHSUBCOORDSNVPROC pathSubCoords = nullptr; + PFNGLPATHSTRINGNVPROC pathString = nullptr; + PFNGLPATHGLYPHSNVPROC pathGlyphs = nullptr; + PFNGLPATHGLYPHRANGENVPROC pathGlyphRange = nullptr; + PFNGLWEIGHTPATHSNVPROC weightPaths = nullptr; + PFNGLCOPYPATHNVPROC copyPath = nullptr; + PFNGLINTERPOLATEPATHSNVPROC interpolatePaths = nullptr; + PFNGLTRANSFORMPATHNVPROC transformPath = nullptr; + PFNGLPATHPARAMETERIVNVPROC pathParameteriv = nullptr; + PFNGLPATHPARAMETERINVPROC pathParameteri = nullptr; + PFNGLPATHPARAMETERFVNVPROC pathParameterfv = nullptr; + PFNGLPATHPARAMETERFNVPROC pathParameterf = nullptr; + PFNGLPATHDASHARRAYNVPROC pathDashArray = nullptr; + PFNGLPATHSTENCILFUNCNVPROC pathStencilFunc = nullptr; + PFNGLPATHSTENCILDEPTHOFFSETNVPROC pathStencilDepthOffset = nullptr; + PFNGLSTENCILFILLPATHNVPROC stencilFillPath = nullptr; + PFNGLSTENCILSTROKEPATHNVPROC stencilStrokePath = nullptr; + PFNGLSTENCILFILLPATHINSTANCEDNVPROC stencilFillPathInstanced = nullptr; + PFNGLSTENCILSTROKEPATHINSTANCEDNVPROC stencilStrokePathInstanced = nullptr; + PFNGLPATHCOVERDEPTHFUNCNVPROC pathCoverDepthFunc = nullptr; + PFNGLPATHCOLORGENNVPROC pathColorGen = nullptr; + PFNGLPATHTEXGENNVPROC pathTexGen = nullptr; + PFNGLPATHFOGGENNVPROC pathFogGen = nullptr; + PFNGLCOVERFILLPATHNVPROC coverFillPath = nullptr; + PFNGLCOVERSTROKEPATHNVPROC coverStrokePath = nullptr; + PFNGLCOVERFILLPATHINSTANCEDNVPROC coverFillPathInstanced = nullptr; + PFNGLCOVERSTROKEPATHINSTANCEDNVPROC coverStrokePathInstanced = nullptr; + PFNGLGETPATHPARAMETERIVNVPROC getPathParameteriv = nullptr; + PFNGLGETPATHPARAMETERFVNVPROC getPathParameterfv = nullptr; + PFNGLGETPATHCOMMANDSNVPROC getPathCommands = nullptr; + PFNGLGETPATHCOORDSNVPROC getPathCoords = nullptr; + PFNGLGETPATHDASHARRAYNVPROC getPathDashArray = nullptr; + PFNGLGETPATHMETRICSNVPROC getPathMetrics = nullptr; + PFNGLGETPATHMETRICRANGENVPROC getPathMetricRange = nullptr; + PFNGLGETPATHSPACINGNVPROC getPathSpacing = nullptr; + PFNGLGETPATHCOLORGENIVNVPROC getPathColorgeniv = nullptr; + PFNGLGETPATHCOLORGENFVNVPROC getPathColorgenfv = nullptr; + PFNGLGETPATHTEXGENIVNVPROC getPathTexGeniv = nullptr; + PFNGLGETPATHTEXGENFVNVPROC getPathTexGenfv = nullptr; + PFNGLISPOINTINFILLPATHNVPROC isPointInFillPath = nullptr; + PFNGLISPOINTINSTROKEPATHNVPROC isPointInStrokePath = nullptr; + PFNGLGETPATHLENGTHNVPROC getPathLength = nullptr; + PFNGLPOINTALONGPATHNVPROC getPointAlongPath = nullptr; + PFNGLMATRIXLOAD3X2FNVPROC matrixLoad3x2f = nullptr; + PFNGLMATRIXLOAD3X3FNVPROC matrixLoad3x3f = nullptr; + PFNGLMATRIXLOADTRANSPOSE3X3FNVPROC matrixLoadTranspose3x3f = nullptr; + PFNGLMATRIXMULT3X2FNVPROC matrixMult3x2f = nullptr; + PFNGLMATRIXMULT3X3FNVPROC matrixMult3x3f = nullptr; + PFNGLMATRIXMULTTRANSPOSE3X3FNVPROC matrixMultTranspose3x3f = nullptr; + PFNGLSTENCILTHENCOVERFILLPATHNVPROC stencilThenCoverFillPath = nullptr; + PFNGLSTENCILTHENCOVERSTROKEPATHNVPROC stencilThenCoverStrokePath = nullptr; + PFNGLSTENCILTHENCOVERFILLPATHINSTANCEDNVPROC stencilThenCoverFillPathInstanced = nullptr; + PFNGLSTENCILTHENCOVERSTROKEPATHINSTANCEDNVPROC stencilThenCoverStrokePathInstanced = nullptr; + PFNGLPATHGLYPHINDEXRANGENVPROC pathGlyphIndexRange = nullptr; + PFNGLPATHGLYPHINDEXARRAYNVPROC pathGlyphIndexArray = nullptr; + PFNGLPATHMEMORYGLYPHINDEXARRAYNVPROC pathMemoryGlyphIndexArray = nullptr; + PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC programPathFragmentInputGen = nullptr; + PFNGLGETPROGRAMRESOURCEFVNVPROC getProgramResourcefv = nullptr; + + PFNGLMATRIXLOADFEXTPROC matrixLoadf = nullptr; + PFNGLMATRIXLOADIDENTITYEXTPROC matrixLoadIdentity = nullptr; + +private: + QQuickNvprFunctionsPrivate *d; +}; + +QT_END_NAMESPACE + +#endif // QT_NO_OPENGL + +#endif // QQUICKNVPRFUNCTIONS_P_H diff --git a/src/quick/util/qquicknvprfunctions_p_p.h b/src/quick/util/qquicknvprfunctions_p_p.h new file mode 100644 index 0000000000..6df20566af --- /dev/null +++ b/src/quick/util/qquicknvprfunctions_p_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKNVPRFUNCTIONS_P_P_H +#define QQUICKNVPRFUNCTIONS_P_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of a number of Qt sources files. This header file may change from +// version to version without notice, or even be removed. +// +// We mean it. +// + +#include "qquicknvprfunctions_p.h" + +QT_BEGIN_NAMESPACE + +class QQuickNvprFunctionsPrivate +{ +public: + QQuickNvprFunctionsPrivate(QQuickNvprFunctions *q_ptr) : q(q_ptr) { } + + bool resolve(); + + QQuickNvprFunctions *q; +}; + +QT_END_NAMESPACE + +#endif // QQUICKNVPRFUNCTIONS_P_P_H diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index 25a4433a9b..a6fa21d696 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -68,7 +68,7 @@ QT_BEGIN_NAMESPACE \instantiates QQuickPath \inqmlmodule QtQuick \ingroup qtquick-animation-paths - \brief Defines a path for use by \l PathView + \brief Defines a path for use by \l PathView and \l PathItem A Path is composed of one or more path segments - PathLine, PathQuad, PathCubic, PathArc, PathCurve, PathSvg. @@ -79,7 +79,7 @@ QT_BEGIN_NAMESPACE PathAttribute allows named attributes with values to be defined along the path. - \sa PathView, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic, PathArc, PathCurve, PathSvg + \sa PathView, PathItem, PathAttribute, PathPercent, PathLine, PathMove, PathQuad, PathCubic, PathArc, PathCurve, PathSvg */ QQuickPath::QQuickPath(QObject *parent) : QObject(*(new QQuickPathPrivate), parent) @@ -1017,7 +1017,7 @@ void QQuickPathAttribute::setValue(qreal value) } \endqml - \sa Path, PathQuad, PathCubic, PathArc, PathCurve, PathSvg + \sa Path, PathQuad, PathCubic, PathArc, PathCurve, PathSvg, PathMove */ /*! @@ -1060,6 +1060,66 @@ void QQuickPathLine::addToPath(QPainterPath &path, const QQuickPathData &data) /****************************************************************************/ /*! + \qmltype PathMove + \instantiates QQuickPathMove + \inqmlmodule QtQuick + \ingroup qtquick-animation-paths + \brief Moves the Path's position + + While not relevant with PathView, for Path elements used with PathItem it + is important to distinguish between the operations of drawing a straight + line and moving the path position without drawing anything. + + \note PathMove should not be used in a Path associated with a PathView. Use + PathLine instead. + + The example below creates a path consisting of two horizontal lines with + some empty space between them. All three segments have a width of 100: + + \qml + Path { + startX: 0; startY: 100 + PathLine { relativeX: 100; y: 100 } + PathMove { relativeX: 100; y: 100 } + PathLine { relativeX: 100; y: 100 } + } + \endqml + + \sa Path, PathQuad, PathCubic, PathArc, PathCurve, PathSvg, PathLine +*/ + +/*! + \qmlproperty real QtQuick::PathMove::x + \qmlproperty real QtQuick::PathMove::y + + Defines the position to move to. + + \sa relativeX, relativeY +*/ + +/*! + \qmlproperty real QtQuick::PathMove::relativeX + \qmlproperty real QtQuick::PathMove::relativeY + + Defines the position to move to relative to its start. + + If both a relative and absolute end position are specified for a single axis, the relative + position will be used. + + Relative and absolute positions can be mixed, for example it is valid to set a relative x + and an absolute y. + + \sa x, y +*/ + +void QQuickPathMove::addToPath(QPainterPath &path, const QQuickPathData &data) +{ + path.moveTo(positionForCurve(data, path.currentPosition())); +} + +/****************************************************************************/ + +/*! \qmltype PathQuad \instantiates QQuickPathQuad \inqmlmodule QtQuick @@ -1655,6 +1715,7 @@ void QQuickPathArc::setRadiusX(qreal radius) _radiusX = radius; emit radiusXChanged(); + emit changed(); } qreal QQuickPathArc::radiusY() const @@ -1669,6 +1730,7 @@ void QQuickPathArc::setRadiusY(qreal radius) _radiusY = radius; emit radiusYChanged(); + emit changed(); } /*! @@ -1702,6 +1764,7 @@ void QQuickPathArc::setUseLargeArc(bool largeArc) _useLargeArc = largeArc; emit useLargeArcChanged(); + emit changed(); } /*! @@ -1733,6 +1796,7 @@ void QQuickPathArc::setDirection(ArcDirection direction) _direction = direction; emit directionChanged(); + emit changed(); } void QQuickPathArc::addToPath(QPainterPath &path, const QQuickPathData &data) diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h index 06ad389b49..283283f377 100644 --- a/src/quick/util/qquickpath_p.h +++ b/src/quick/util/qquickpath_p.h @@ -159,6 +159,15 @@ public: void addToPath(QPainterPath &path, const QQuickPathData &) override; }; +class Q_QUICK_PRIVATE_EXPORT QQuickPathMove : public QQuickCurve +{ + Q_OBJECT +public: + QQuickPathMove(QObject *parent=0) : QQuickCurve(parent) {} + + void addToPath(QPainterPath &path, const QQuickPathData &) override; +}; + class Q_QUICK_PRIVATE_EXPORT QQuickPathQuad : public QQuickCurve { Q_OBJECT @@ -459,6 +468,7 @@ QML_DECLARE_TYPE(QQuickPathElement) QML_DECLARE_TYPE(QQuickPathAttribute) QML_DECLARE_TYPE(QQuickCurve) QML_DECLARE_TYPE(QQuickPathLine) +QML_DECLARE_TYPE(QQuickPathMove) QML_DECLARE_TYPE(QQuickPathQuad) QML_DECLARE_TYPE(QQuickPathCubic) QML_DECLARE_TYPE(QQuickPathCatmullRomCurve) diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index 1ef1018a31..22f23f7598 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -74,4 +74,11 @@ qtConfig(quick-path) { $$PWD/qquickpath_p.h \ $$PWD/qquickpath_p_p.h \ $$PWD/qquickpathinterpolator_p.h + qtConfig(opengl) { + SOURCES += \ + $$PWD/qquicknvprfunctions.cpp + HEADERS += \ + $$PWD/qquicknvprfunctions_p.h \ + $$PWD/qquicknvprfunctions_p_p.h + } } |