diff options
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 + } } |