From 55db3890f44c7bef9a6ecb2b2f3bf31e288a3cd8 Mon Sep 17 00:00:00 2001 From: Paolo Angelelli Date: Tue, 10 Apr 2018 17:33:19 +0200 Subject: Move QtQuick.Shapes implementation to qtquickshapes, privately exported This change moves the implementation of QtQuick.Shapes into an own qt module, where classes are privately exported. In this way Shapes QML types can be internally (= from other Qt modules) instantiated also from cpp. Change-Id: I428f981f0a1f3083e6571cbeaffa706fd8ef7254 Reviewed-by: Shawn Rutledge Reviewed-by: Laszlo Agocs --- src/imports/shapes/plugin.cpp | 9 +- src/imports/shapes/qquicknvprfunctions.cpp | 281 ---- src/imports/shapes/qquicknvprfunctions_p.h | 400 ----- src/imports/shapes/qquicknvprfunctions_p_p.h | 70 - src/imports/shapes/qquickshape.cpp | 1607 ------------------- src/imports/shapes/qquickshape_p.h | 376 ----- src/imports/shapes/qquickshape_p_p.h | 231 --- src/imports/shapes/qquickshapegenericrenderer.cpp | 1007 ------------ src/imports/shapes/qquickshapegenericrenderer_p.h | 392 ----- src/imports/shapes/qquickshapenvprrenderer.cpp | 1001 ------------ src/imports/shapes/qquickshapenvprrenderer_p.h | 237 --- src/imports/shapes/qquickshapesoftwarerenderer.cpp | 282 ---- src/imports/shapes/qquickshapesoftwarerenderer_p.h | 135 -- src/imports/shapes/qtquickshapesplugin.qrc | 20 - src/imports/shapes/shaders/blit.frag | 9 - src/imports/shapes/shaders/blit.vert | 12 - src/imports/shapes/shaders/blit_core.frag | 13 - src/imports/shapes/shaders/blit_core.vert | 14 - src/imports/shapes/shaders/conicalgradient.frag | 19 - src/imports/shapes/shaders/conicalgradient.vert | 13 - .../shapes/shaders/conicalgradient_core.frag | 22 - .../shapes/shaders/conicalgradient_core.vert | 15 - src/imports/shapes/shaders/lineargradient.frag | 9 - src/imports/shapes/shaders/lineargradient.vert | 15 - .../shapes/shaders/lineargradient_core.frag | 12 - .../shapes/shaders/lineargradient_core.vert | 17 - src/imports/shapes/shaders/radialgradient.frag | 25 - src/imports/shapes/shaders/radialgradient.vert | 13 - .../shapes/shaders/radialgradient_core.frag | 29 - .../shapes/shaders/radialgradient_core.vert | 15 - src/imports/shapes/shapes.pro | 24 +- src/quickshapes/qquicknvprfunctions.cpp | 281 ++++ src/quickshapes/qquicknvprfunctions_p.h | 401 +++++ src/quickshapes/qquicknvprfunctions_p_p.h | 71 + src/quickshapes/qquickshape.cpp | 1620 ++++++++++++++++++++ src/quickshapes/qquickshape_p.h | 377 +++++ src/quickshapes/qquickshape_p_p.h | 232 +++ src/quickshapes/qquickshapegenericrenderer.cpp | 1007 ++++++++++++ src/quickshapes/qquickshapegenericrenderer_p.h | 393 +++++ src/quickshapes/qquickshapenvprrenderer.cpp | 1001 ++++++++++++ src/quickshapes/qquickshapenvprrenderer_p.h | 238 +++ src/quickshapes/qquickshapesglobal.h | 56 + src/quickshapes/qquickshapesglobal_p.h | 63 + src/quickshapes/qquickshapesoftwarerenderer.cpp | 282 ++++ src/quickshapes/qquickshapesoftwarerenderer_p.h | 136 ++ src/quickshapes/qtquickshapes.qrc | 20 + src/quickshapes/quickshapes.pro | 33 + src/quickshapes/shaders/blit.frag | 9 + src/quickshapes/shaders/blit.vert | 12 + src/quickshapes/shaders/blit_core.frag | 13 + src/quickshapes/shaders/blit_core.vert | 14 + src/quickshapes/shaders/conicalgradient.frag | 19 + src/quickshapes/shaders/conicalgradient.vert | 13 + src/quickshapes/shaders/conicalgradient_core.frag | 22 + src/quickshapes/shaders/conicalgradient_core.vert | 15 + src/quickshapes/shaders/lineargradient.frag | 9 + src/quickshapes/shaders/lineargradient.vert | 15 + src/quickshapes/shaders/lineargradient_core.frag | 12 + src/quickshapes/shaders/lineargradient_core.vert | 17 + src/quickshapes/shaders/radialgradient.frag | 25 + src/quickshapes/shaders/radialgradient.vert | 13 + src/quickshapes/shaders/radialgradient_core.frag | 29 + src/quickshapes/shaders/radialgradient_core.vert | 15 + src/src.pro | 5 +- sync.profile | 1 + tests/auto/quick/qquickshape/qquickshape.pro | 24 +- tests/auto/quick/qquickshape/tst_qquickshape.cpp | 2 +- 67 files changed, 6477 insertions(+), 6342 deletions(-) delete mode 100644 src/imports/shapes/qquicknvprfunctions.cpp delete mode 100644 src/imports/shapes/qquicknvprfunctions_p.h delete mode 100644 src/imports/shapes/qquicknvprfunctions_p_p.h delete mode 100644 src/imports/shapes/qquickshape.cpp delete mode 100644 src/imports/shapes/qquickshape_p.h delete mode 100644 src/imports/shapes/qquickshape_p_p.h delete mode 100644 src/imports/shapes/qquickshapegenericrenderer.cpp delete mode 100644 src/imports/shapes/qquickshapegenericrenderer_p.h delete mode 100644 src/imports/shapes/qquickshapenvprrenderer.cpp delete mode 100644 src/imports/shapes/qquickshapenvprrenderer_p.h delete mode 100644 src/imports/shapes/qquickshapesoftwarerenderer.cpp delete mode 100644 src/imports/shapes/qquickshapesoftwarerenderer_p.h delete mode 100644 src/imports/shapes/qtquickshapesplugin.qrc delete mode 100644 src/imports/shapes/shaders/blit.frag delete mode 100644 src/imports/shapes/shaders/blit.vert delete mode 100644 src/imports/shapes/shaders/blit_core.frag delete mode 100644 src/imports/shapes/shaders/blit_core.vert delete mode 100644 src/imports/shapes/shaders/conicalgradient.frag delete mode 100644 src/imports/shapes/shaders/conicalgradient.vert delete mode 100644 src/imports/shapes/shaders/conicalgradient_core.frag delete mode 100644 src/imports/shapes/shaders/conicalgradient_core.vert delete mode 100644 src/imports/shapes/shaders/lineargradient.frag delete mode 100644 src/imports/shapes/shaders/lineargradient.vert delete mode 100644 src/imports/shapes/shaders/lineargradient_core.frag delete mode 100644 src/imports/shapes/shaders/lineargradient_core.vert delete mode 100644 src/imports/shapes/shaders/radialgradient.frag delete mode 100644 src/imports/shapes/shaders/radialgradient.vert delete mode 100644 src/imports/shapes/shaders/radialgradient_core.frag delete mode 100644 src/imports/shapes/shaders/radialgradient_core.vert create mode 100644 src/quickshapes/qquicknvprfunctions.cpp create mode 100644 src/quickshapes/qquicknvprfunctions_p.h create mode 100644 src/quickshapes/qquicknvprfunctions_p_p.h create mode 100644 src/quickshapes/qquickshape.cpp create mode 100644 src/quickshapes/qquickshape_p.h create mode 100644 src/quickshapes/qquickshape_p_p.h create mode 100644 src/quickshapes/qquickshapegenericrenderer.cpp create mode 100644 src/quickshapes/qquickshapegenericrenderer_p.h create mode 100644 src/quickshapes/qquickshapenvprrenderer.cpp create mode 100644 src/quickshapes/qquickshapenvprrenderer_p.h create mode 100644 src/quickshapes/qquickshapesglobal.h create mode 100644 src/quickshapes/qquickshapesglobal_p.h create mode 100644 src/quickshapes/qquickshapesoftwarerenderer.cpp create mode 100644 src/quickshapes/qquickshapesoftwarerenderer_p.h create mode 100644 src/quickshapes/qtquickshapes.qrc create mode 100644 src/quickshapes/quickshapes.pro create mode 100644 src/quickshapes/shaders/blit.frag create mode 100644 src/quickshapes/shaders/blit.vert create mode 100644 src/quickshapes/shaders/blit_core.frag create mode 100644 src/quickshapes/shaders/blit_core.vert create mode 100644 src/quickshapes/shaders/conicalgradient.frag create mode 100644 src/quickshapes/shaders/conicalgradient.vert create mode 100644 src/quickshapes/shaders/conicalgradient_core.frag create mode 100644 src/quickshapes/shaders/conicalgradient_core.vert create mode 100644 src/quickshapes/shaders/lineargradient.frag create mode 100644 src/quickshapes/shaders/lineargradient.vert create mode 100644 src/quickshapes/shaders/lineargradient_core.frag create mode 100644 src/quickshapes/shaders/lineargradient_core.vert create mode 100644 src/quickshapes/shaders/radialgradient.frag create mode 100644 src/quickshapes/shaders/radialgradient.vert create mode 100644 src/quickshapes/shaders/radialgradient_core.frag create mode 100644 src/quickshapes/shaders/radialgradient_core.vert diff --git a/src/imports/shapes/plugin.cpp b/src/imports/shapes/plugin.cpp index f2635d2995..e3a9017681 100644 --- a/src/imports/shapes/plugin.cpp +++ b/src/imports/shapes/plugin.cpp @@ -39,8 +39,7 @@ #include #include - -#include "qquickshape_p.h" +#include QT_BEGIN_NAMESPACE @@ -50,7 +49,11 @@ class QmlShapesPlugin : public QQmlExtensionPlugin Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) public: - QmlShapesPlugin(QObject *parent = nullptr) : QQmlExtensionPlugin(parent) { } + QmlShapesPlugin(QObject *parent = nullptr) + : QQmlExtensionPlugin(parent) + { + } + void registerTypes(const char *uri) override { Q_ASSERT(QByteArray(uri) == QByteArray("QtQuick.Shapes")); diff --git a/src/imports/shapes/qquicknvprfunctions.cpp b/src/imports/shapes/qquicknvprfunctions.cpp deleted file mode 100644 index 409a59be7f..0000000000 --- a/src/imports/shapes/qquicknvprfunctions.cpp +++ /dev/null @@ -1,281 +0,0 @@ -/**************************************************************************** -** -** 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" - -#if QT_CONFIG(opengl) - -#include -#include -#include -#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; -} - -#define PROC(type, name) reinterpret_cast(ctx->getProcAddress(#name)) - -/*! - \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 tempContext; - QScopedPointer 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; - - // Check that GL_NV_Path_rendering extension is at least API revision 1.3 - if (!PROC(PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC, glProgramPathFragmentInputGenNV)) - 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; -} - -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->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->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_CONFIG(opengl) diff --git a/src/imports/shapes/qquicknvprfunctions_p.h b/src/imports/shapes/qquicknvprfunctions_p.h deleted file mode 100644 index 342e92cbc3..0000000000 --- a/src/imports/shapes/qquicknvprfunctions_p.h +++ /dev/null @@ -1,400 +0,0 @@ -/**************************************************************************** -** -** 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 -#include - -#if QT_CONFIG(opengl) - -QT_BEGIN_NAMESPACE - -// note: fixed pipeline specific functions are removed - modern ES ext -// headers have all this, but not the fixed stuff - -#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 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 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 - -// this one originates from fixed pipeline so may not be in GLES ext headers, but we need it still -#ifndef GL_OBJECT_LINEAR_NV -#define GL_OBJECT_LINEAR_NV 0x2401 -#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; - 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; - 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_CONFIG(opengl) - -#endif // QQUICKNVPRFUNCTIONS_P_H diff --git a/src/imports/shapes/qquicknvprfunctions_p_p.h b/src/imports/shapes/qquicknvprfunctions_p_p.h deleted file mode 100644 index 6df20566af..0000000000 --- a/src/imports/shapes/qquicknvprfunctions_p_p.h +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** -** -** 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/imports/shapes/qquickshape.cpp b/src/imports/shapes/qquickshape.cpp deleted file mode 100644 index 067a54736f..0000000000 --- a/src/imports/shapes/qquickshape.cpp +++ /dev/null @@ -1,1607 +0,0 @@ -/**************************************************************************** -** -** 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 "qquickshape_p.h" -#include "qquickshape_p_p.h" -#include "qquickshapegenericrenderer_p.h" -#include "qquickshapenvprrenderer_p.h" -#include "qquickshapesoftwarerenderer_p.h" -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(QQSHAPE_LOG_TIME_DIRTY_SYNC, "qt.shape.time.sync") - -/*! - \qmlmodule QtQuick.Shapes 1.11 - \title Qt Quick Shapes QML Types - \ingroup qmlmodules - \brief Provides QML types for drawing stroked and filled shapes. - - To use the types in this module, import the module with the following line: - - \badcode - import QtQuick.Shapes 1.11 - \endcode -*/ - -QQuickShapeStrokeFillParams::QQuickShapeStrokeFillParams() - : strokeColor(Qt::white), - strokeWidth(1), - fillColor(Qt::white), - fillRule(QQuickShapePath::OddEvenFill), - joinStyle(QQuickShapePath::BevelJoin), - miterLimit(2), - capStyle(QQuickShapePath::SquareCap), - strokeStyle(QQuickShapePath::SolidLine), - dashOffset(0), - fillGradient(nullptr) -{ - dashPattern << 4 << 2; // 4 * strokeWidth dash followed by 2 * strokeWidth space -} - -/*! - \qmltype ShapePath - \instantiates QQuickShapePath - \inqmlmodule QtQuick.Shapes - \ingroup qtquick-paths - \ingroup qtquick-views - \inherits Path - \brief Describes a Path and associated properties for stroking and filling. - \since 5.10 - - A \l Shape contains one or more ShapePath elements. At least one ShapePath is - necessary in order to have a Shape output anything visible. A ShapePath - itself is a \l Path with additional properties describing the stroking and - filling parameters, such as the stroke width and color, the fill color or - gradient, join and cap styles, and so on. As with ordinary \l Path objects, - ShapePath also contains a list of path elements like \l PathMove, \l PathLine, - \l PathCubic, \l PathQuad, \l PathArc, together with a starting position. - - Any property changes in these data sets will be bubble up and change the - output of the Shape. This means that it is simple and easy to change, or - even animate, the starting and ending position, control points, or any - stroke or fill parameters using the usual QML bindings and animation types - like NumberAnimation. - - In the following example the line join style changes automatically based on - the value of joinStyleIndex: - - \qml - ShapePath { - strokeColor: "black" - strokeWidth: 16 - fillColor: "transparent" - capStyle: ShapePath.RoundCap - - property int joinStyleIndex: 0 - - property variant styles: [ - ShapePath.BevelJoin, - ShapePath.MiterJoin, - ShapePath.RoundJoin - ] - - joinStyle: styles[joinStyleIndex] - - startX: 30 - startY: 30 - PathLine { x: 100; y: 100 } - PathLine { x: 30; y: 100 } - } - \endqml - - Once associated with a Shape, here is the output with a joinStyleIndex - of 2 (ShapePath.RoundJoin): - - \image visualpath-code-example.png - - \sa {Qt Quick Examples - Shapes}, Shape - */ - -QQuickShapePathPrivate::QQuickShapePathPrivate() - : dirty(DirtyAll) -{ - // Set this QQuickPath to be a ShapePath - isShapePath = true; -} - -QQuickShapePath::QQuickShapePath(QObject *parent) - : QQuickPath(*(new QQuickShapePathPrivate), parent) -{ - // The inherited changed() and the shapePathChanged() signals remain - // distinct, and this is intentional. Combining the two is not possible due - // to the difference in semantics and the need to act (see dirty flag - // below) differently on QQuickPath-related changes. - - connect(this, &QQuickPath::changed, [this]() { - Q_D(QQuickShapePath); - d->dirty |= QQuickShapePathPrivate::DirtyPath; - emit shapePathChanged(); - }); -} - -QQuickShapePath::~QQuickShapePath() -{ -} - -/*! - \qmlproperty color QtQuick.Shapes::ShapePath::strokeColor - - This property holds the stroking color. - - When set to \c transparent, no stroking occurs. - - The default value is \c white. - */ - -QColor QQuickShapePath::strokeColor() const -{ - Q_D(const QQuickShapePath); - return d->sfp.strokeColor; -} - -void QQuickShapePath::setStrokeColor(const QColor &color) -{ - Q_D(QQuickShapePath); - if (d->sfp.strokeColor != color) { - d->sfp.strokeColor = color; - d->dirty |= QQuickShapePathPrivate::DirtyStrokeColor; - emit strokeColorChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty color QtQuick.Shapes::ShapePath::strokeWidth - - This property holds the stroke width. - - When set to a negative value, no stroking occurs. - - The default value is 1. - */ - -qreal QQuickShapePath::strokeWidth() const -{ - Q_D(const QQuickShapePath); - return d->sfp.strokeWidth; -} - -void QQuickShapePath::setStrokeWidth(qreal w) -{ - Q_D(QQuickShapePath); - if (d->sfp.strokeWidth != w) { - d->sfp.strokeWidth = w; - d->dirty |= QQuickShapePathPrivate::DirtyStrokeWidth; - emit strokeWidthChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty color QtQuick.Shapes::ShapePath::fillColor - - This property holds the fill color. - - When set to \c transparent, no filling occurs. - - The default value is \c white. - */ - -QColor QQuickShapePath::fillColor() const -{ - Q_D(const QQuickShapePath); - return d->sfp.fillColor; -} - -void QQuickShapePath::setFillColor(const QColor &color) -{ - Q_D(QQuickShapePath); - if (d->sfp.fillColor != color) { - d->sfp.fillColor = color; - d->dirty |= QQuickShapePathPrivate::DirtyFillColor; - emit fillColorChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty enumeration QtQuick.Shapes::ShapePath::fillRule - - This property holds the fill rule. The default value is - \c ShapePath.OddEvenFill. For an explanation on fill rules, see - QPainterPath::setFillRule(). - - \value ShapePath.OddEvenFill - Odd-even fill rule. - - \value ShapePath.WindingFill - Non-zero winding fill rule. - */ - -QQuickShapePath::FillRule QQuickShapePath::fillRule() const -{ - Q_D(const QQuickShapePath); - return d->sfp.fillRule; -} - -void QQuickShapePath::setFillRule(FillRule fillRule) -{ - Q_D(QQuickShapePath); - if (d->sfp.fillRule != fillRule) { - d->sfp.fillRule = fillRule; - d->dirty |= QQuickShapePathPrivate::DirtyFillRule; - emit fillRuleChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty enumeration QtQuick.Shapes::ShapePath::joinStyle - - This property defines how joins between two connected lines are drawn. The - default value is \c ShapePath.BevelJoin. - - \value ShapePath.MiterJoin - The outer edges of the lines are extended to meet at an angle, and - this area is filled. - - \value ShapePath.BevelJoin - The triangular notch between the two lines is filled. - - \value ShapePath.RoundJoin - A circular arc between the two lines is filled. - */ - -QQuickShapePath::JoinStyle QQuickShapePath::joinStyle() const -{ - Q_D(const QQuickShapePath); - return d->sfp.joinStyle; -} - -void QQuickShapePath::setJoinStyle(JoinStyle style) -{ - Q_D(QQuickShapePath); - if (d->sfp.joinStyle != style) { - d->sfp.joinStyle = style; - d->dirty |= QQuickShapePathPrivate::DirtyStyle; - emit joinStyleChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty int QtQuick.Shapes::ShapePath::miterLimit - - When joinStyle is set to \c ShapePath.MiterJoin, this property - specifies how far the miter join can extend from the join point. - - The default value is 2. - */ - -int QQuickShapePath::miterLimit() const -{ - Q_D(const QQuickShapePath); - return d->sfp.miterLimit; -} - -void QQuickShapePath::setMiterLimit(int limit) -{ - Q_D(QQuickShapePath); - if (d->sfp.miterLimit != limit) { - d->sfp.miterLimit = limit; - d->dirty |= QQuickShapePathPrivate::DirtyStyle; - emit miterLimitChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty enumeration QtQuick.Shapes::ShapePath::capStyle - - This property defines how the end points of lines are drawn. The - default value is \c ShapePath.SquareCap. - - \value ShapePath.FlatCap - A square line end that does not cover the end point of the line. - - \value ShapePath.SquareCap - A square line end that covers the end point and extends beyond it - by half the line width. - - \value ShapePath.RoundCap - A rounded line end. - */ - -QQuickShapePath::CapStyle QQuickShapePath::capStyle() const -{ - Q_D(const QQuickShapePath); - return d->sfp.capStyle; -} - -void QQuickShapePath::setCapStyle(CapStyle style) -{ - Q_D(QQuickShapePath); - if (d->sfp.capStyle != style) { - d->sfp.capStyle = style; - d->dirty |= QQuickShapePathPrivate::DirtyStyle; - emit capStyleChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty enumeration QtQuick.Shapes::ShapePath::strokeStyle - - This property defines the style of stroking. The default value is - ShapePath.SolidLine. - - \list - \li ShapePath.SolidLine - A plain line. - \li ShapePath.DashLine - Dashes separated by a few pixels. - \endlist - */ - -QQuickShapePath::StrokeStyle QQuickShapePath::strokeStyle() const -{ - Q_D(const QQuickShapePath); - return d->sfp.strokeStyle; -} - -void QQuickShapePath::setStrokeStyle(StrokeStyle style) -{ - Q_D(QQuickShapePath); - if (d->sfp.strokeStyle != style) { - d->sfp.strokeStyle = style; - d->dirty |= QQuickShapePathPrivate::DirtyDash; - emit strokeStyleChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty real QtQuick.Shapes::ShapePath::dashOffset - - This property defines the starting point on the dash pattern, measured in - units used to specify the dash pattern. - - The default value is 0. - - \sa QPen::setDashOffset() - */ - -qreal QQuickShapePath::dashOffset() const -{ - Q_D(const QQuickShapePath); - return d->sfp.dashOffset; -} - -void QQuickShapePath::setDashOffset(qreal offset) -{ - Q_D(QQuickShapePath); - if (d->sfp.dashOffset != offset) { - d->sfp.dashOffset = offset; - d->dirty |= QQuickShapePathPrivate::DirtyDash; - emit dashOffsetChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty list QtQuick.Shapes::ShapePath::dashPattern - - This property defines the dash pattern when ShapePath.strokeStyle is set - to ShapePath.DashLine. The pattern must be specified as an even number of - positive entries where the entries 1, 3, 5... are the dashes and 2, 4, - 6... are the spaces. The pattern is specified in units of the pen's width. - - The default value is (4, 2), meaning a dash of 4 * ShapePath.strokeWidth - pixels followed by a space of 2 * ShapePath.strokeWidth pixels. - - \sa QPen::setDashPattern() - */ - -QVector QQuickShapePath::dashPattern() const -{ - Q_D(const QQuickShapePath); - return d->sfp.dashPattern; -} - -void QQuickShapePath::setDashPattern(const QVector &array) -{ - Q_D(QQuickShapePath); - if (d->sfp.dashPattern != array) { - d->sfp.dashPattern = array; - d->dirty |= QQuickShapePathPrivate::DirtyDash; - emit dashPatternChanged(); - emit shapePathChanged(); - } -} - -/*! - \qmlproperty ShapeGradient QtQuick.Shapes::ShapePath::fillGradient - - This property defines the fill gradient. By default no gradient is enabled - and the value is \c null. In this case the fill uses a solid color based - on the value of ShapePath.fillColor. - - When set, ShapePath.fillColor is ignored and filling is done using one of - the ShapeGradient subtypes. - - \note The Gradient type cannot be used here. Rather, prefer using one of - the advanced subtypes, like LinearGradient. - */ - -QQuickShapeGradient *QQuickShapePath::fillGradient() const -{ - Q_D(const QQuickShapePath); - return d->sfp.fillGradient; -} - -void QQuickShapePath::setFillGradient(QQuickShapeGradient *gradient) -{ - Q_D(QQuickShapePath); - if (d->sfp.fillGradient != gradient) { - if (d->sfp.fillGradient) - qmlobject_disconnect(d->sfp.fillGradient, QQuickShapeGradient, SIGNAL(updated()), - this, QQuickShapePath, SLOT(_q_fillGradientChanged())); - d->sfp.fillGradient = gradient; - if (d->sfp.fillGradient) - qmlobject_connect(d->sfp.fillGradient, QQuickShapeGradient, SIGNAL(updated()), - this, QQuickShapePath, SLOT(_q_fillGradientChanged())); - d->dirty |= QQuickShapePathPrivate::DirtyFillGradient; - emit shapePathChanged(); - } -} - -void QQuickShapePathPrivate::_q_fillGradientChanged() -{ - Q_Q(QQuickShapePath); - dirty |= DirtyFillGradient; - emit q->shapePathChanged(); -} - -void QQuickShapePath::resetFillGradient() -{ - setFillGradient(nullptr); -} - -/*! - \qmltype Shape - \instantiates QQuickShape - \inqmlmodule QtQuick.Shapes - \ingroup qtquick-paths - \ingroup qtquick-views - \inherits Item - \brief Renders a path. - \since 5.10 - - Renders a path either by generating geometry via QPainterPath and manual - triangulation or by using a GPU vendor 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 Shape is suitable for creating shapes spreading over larger - areas of the screen, avoiding the performance penalty for texture uploads - or framebuffer blits. In addition, the declarative API allows manipulating, - binding to, and even animating the path element properties like starting - and ending position, the control points, and so on. - - The types for specifying path elements are shared between \l PathView and - Shape. However, not all Shape implementations support all path - element types, while some may not make sense for PathView. Shape's - currently supported subset is: PathMove, PathLine, PathQuad, PathCubic, - PathArc, and PathSvg. - - See \l Path for a detailed overview of the supported path elements. - - \qml - Shape { - width: 200 - height: 150 - anchors.centerIn: parent - ShapePath { - strokeWidth: 4 - strokeColor: "red" - fillGradient: LinearGradient { - x1: 20; y1: 20 - x2: 180; y2: 130 - GradientStop { position: 0; color: "blue" } - GradientStop { position: 0.2; color: "green" } - GradientStop { position: 0.4; color: "red" } - GradientStop { position: 0.6; color: "yellow" } - GradientStop { position: 1; color: "cyan" } - } - strokeStyle: ShapePath.DashLine - dashPattern: [ 1, 4 ] - startX: 20; startY: 20 - PathLine { x: 180; y: 130 } - PathLine { x: 20; y: 130 } - PathLine { x: 20; y: 20 } - } - } - \endqml - - \image pathitem-code-example.png - - Like \l Item, Shape also allows any visual or non-visual objects to be - declared as children. ShapePath objects are handled specially. This is - useful since it allows adding visual items, like \l Rectangle or \l Image, - and non-visual objects, like \l Timer directly as children of Shape. - - The following list summarizes the available Shape rendering approaches: - - \list - - \li When running with the default, OpenGL backend of Qt Quick, both the - generic, triangulation-based and the NVIDIA-specific - \c{GL_NV_path_rendering} methods are available. The choice is made at - runtime, depending on the graphics driver's capabilities. When this is not - desired, applications can force using the generic method by setting the - Shape.vendorExtensionsEnabled property to \c false. - - \li The \c software backend is fully supported. The path is rendered via - QPainter::strokePath() and QPainter::fillPath() in this case. - - \li The Direct 3D 12 backend is not currently supported. - - \li The OpenVG backend is not currently supported. - - \endlist - - When using Shape, it is important to be aware of potential performance - implications: - - \list - - \li When the application is running with the generic, triangulation-based - Shape implementation, the geometry generation happens entirely on the - CPU. This is potentially expensive. Changing the set of path elements, - changing the properties of these elements, or changing certain properties - of the Shape itself all lead to retriangulation of the affected paths on - every change. Therefore, applying animation to such properties can affect - performance on less powerful systems. - - \li However, the data-driven, declarative nature of the Shape API often - means better cacheability for the underlying CPU and GPU resources. A - property change in one ShapePath will only lead to reprocessing the - affected ShapePath, leaving other parts of the Shape unchanged. Therefore, - a frequently changing property can still result in a lower overall system - load than with imperative painting approaches (for example, QPainter). - - \li 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 property changes is smaller. - - \li At the same time, attention must be paid to the number of Shape - elements in the scene, in particular when using this special accelerated - approach for \c{GL_NV_path_rendering}. The way such a Shape item is - represented in the scene graph is different from an ordinary - geometry-based item, and incurs a certain cost when it comes to OpenGL - state changes. - - \li As a general rule, scenes should avoid using separate Shape items when - it is not absolutely necessary. Prefer using one Shape item with multiple - ShapePath elements over multiple Shape items. Scenes that cannot avoid - using a large number of individual Shape items should consider setting - Shape.vendorExtensionsEnabled to \c false. - \endlist - - \sa {Qt Quick Examples - Shapes}, Path, PathMove, PathLine, PathQuad, PathCubic, PathArc, PathSvg -*/ - -QQuickShapePrivate::QQuickShapePrivate() - : effectRefCount(0) -{ -} - -QQuickShapePrivate::~QQuickShapePrivate() -{ - delete renderer; -} - -void QQuickShapePrivate::_q_shapePathChanged() -{ - Q_Q(QQuickShape); - spChanged = true; - q->polish(); -} - -void QQuickShapePrivate::setStatus(QQuickShape::Status newStatus) -{ - Q_Q(QQuickShape); - if (status != newStatus) { - status = newStatus; - emit q->statusChanged(); - } -} - -QQuickShape::QQuickShape(QQuickItem *parent) - : QQuickItem(*(new QQuickShapePrivate), parent) -{ - setFlag(ItemHasContents); -} - -QQuickShape::~QQuickShape() -{ -} - -/*! - \qmlproperty enumeration QtQuick.Shapes::Shape::rendererType - - This property determines which path rendering backend is active. - - \value Shape.UnknownRenderer - The renderer is unknown. - - \value Shape.GeometryRenderer - The generic, driver independent solution for OpenGL. Uses the same - CPU-based triangulation approach as QPainter's OpenGL 2 paint - engine. This is the default on non-NVIDIA hardware when the default, - OpenGL Qt Quick scenegraph backend is in use. - - \value Shape.NvprRenderer - Path items are rendered by performing OpenGL calls using the - \c{GL_NV_path_rendering} extension. This is the default on NVIDIA - hardware when the default, OpenGL Qt Quick scenegraph backend is in - use. - - \value Shape.SoftwareRenderer - Pure QPainter drawing using the raster paint engine. This is the - default, and only, option when the Qt Quick scenegraph is running - with the \c software backend. -*/ - -QQuickShape::RendererType QQuickShape::rendererType() const -{ - Q_D(const QQuickShape); - return d->rendererType; -} - -/*! - \qmlproperty bool QtQuick.Shapes::Shape::asynchronous - - When rendererType is \c Shape.GeometryRenderer, the input path is - triangulated on the CPU during the polishing phase of the Shape. This is - potentially expensive. To offload this work to separate worker threads, - set this property to \c true. - - When enabled, making a Shape visible will not wait for the content to - become available. Instead, the gui/main thread is not blocked and the - results of the path rendering are shown only when all the asynchronous - work has been finished. - - The default value is \c false. - */ - -bool QQuickShape::asynchronous() const -{ - Q_D(const QQuickShape); - return d->async; -} - -void QQuickShape::setAsynchronous(bool async) -{ - Q_D(QQuickShape); - if (d->async != async) { - d->async = async; - emit asynchronousChanged(); - if (d->componentComplete) - d->_q_shapePathChanged(); - } -} - -/*! - \qmlproperty bool QtQuick.Shapes::Shape::vendorExtensionsEnabled - - This property controls the usage of non-standard OpenGL extensions like - \c GL_NV_path_rendering. To disable Shape.NvprRenderer and force a uniform - behavior regardless of the graphics card and drivers, set this property to - \c false. - - The default value is \c true. - */ - -bool QQuickShape::vendorExtensionsEnabled() const -{ - Q_D(const QQuickShape); - return d->enableVendorExts; -} - -void QQuickShape::setVendorExtensionsEnabled(bool enable) -{ - Q_D(QQuickShape); - if (d->enableVendorExts != enable) { - d->enableVendorExts = enable; - emit vendorExtensionsEnabledChanged(); - } -} - -/*! - \qmlproperty enumeration QtQuick.Shapes::Shape::status - - This property determines the status of the Shape and is relevant when - Shape.asynchronous is set to \c true. - - \value Shape.Null - Not yet initialized. - - \value Shape.Ready - The Shape has finished processing. - - \value Shape.Processing - The path is being processed. - */ - -QQuickShape::Status QQuickShape::status() const -{ - Q_D(const QQuickShape); - return d->status; -} - -/*! - \qmlproperty enumeration QtQuick.Shapes::Shape::containsMode - \since QtQuick.Shapes 1.11 - - This property determines the definition of \l {QQuickItem::contains()}{contains()} - for the Shape. It is useful in case you add - \l {Qt Quick Pointer Handlers QML Types}{Pointer Handlers} and you - want to react only when the mouse or touchpoint is fully inside the Shape. - - \value Shape.BoundingRectContains - The default implementation of \l QQuickItem::contains() checks only - whether the given point is inside the rectangular bounding box. This is - the most efficient implementation, which is why it's the default. - - \value Shape.FillContains - Check whether the interior (the part that would be filled if you are - rendering it with fill) of any \l ShapePath that makes up this Shape - contains the given point. The more complex and numerous ShapePaths you - add, the less efficient this is to check, which can potentially slow - down event delivery in your application. So it should be used with care. - - One way to speed up the \c FillContains check is to generate an approximate - outline with as few points as possible, place that in a transparent Shape - on top, and add your Pointer Handlers to that, so that the containment - check is cheaper during event delivery. -*/ -QQuickShape::ContainsMode QQuickShape::containsMode() const -{ - Q_D(const QQuickShape); - return d->containsMode; -} - -void QQuickShape::setContainsMode(QQuickShape::ContainsMode containsMode) -{ - Q_D(QQuickShape); - if (d->containsMode == containsMode) - return; - - d->containsMode = containsMode; - emit containsModeChanged(); -} - -bool QQuickShape::contains(const QPointF &point) const -{ - Q_D(const QQuickShape); - switch (d->containsMode) { - case BoundingRectContains: - return QQuickItem::contains(point); - case FillContains: - for (QQuickShapePath *path : d->sp) { - if (path->path().contains(point)) - return true; - } - } - return false; -} - -static void vpe_append(QQmlListProperty *property, QObject *obj) -{ - QQuickShape *item = static_cast(property->object); - QQuickShapePrivate *d = QQuickShapePrivate::get(item); - QQuickShapePath *path = qobject_cast(obj); - if (path) - d->sp.append(path); - - QQuickItemPrivate::data_append(property, obj); - - if (path && d->componentComplete) { - QObject::connect(path, SIGNAL(shapePathChanged()), item, SLOT(_q_shapePathChanged())); - d->_q_shapePathChanged(); - } -} - -static void vpe_clear(QQmlListProperty *property) -{ - QQuickShape *item = static_cast(property->object); - QQuickShapePrivate *d = QQuickShapePrivate::get(item); - - for (QQuickShapePath *p : d->sp) - QObject::disconnect(p, SIGNAL(shapePathChanged()), item, SLOT(_q_shapePathChanged())); - - d->sp.clear(); - - QQuickItemPrivate::data_clear(property); - - if (d->componentComplete) - d->_q_shapePathChanged(); -} - -/*! - \qmlproperty list QtQuick.Shapes::Shape::data - - This property holds the ShapePath objects that define the contents of the - Shape. It can also contain any other type of objects, since Shape, like - Item, allows adding any visual or non-visual objects as children. - - \default - */ - -QQmlListProperty QQuickShape::data() -{ - return QQmlListProperty(this, - nullptr, - vpe_append, - QQuickItemPrivate::data_count, - QQuickItemPrivate::data_at, - vpe_clear); -} - -void QQuickShape::classBegin() -{ - QQuickItem::classBegin(); -} - -void QQuickShape::componentComplete() -{ - Q_D(QQuickShape); - - QQuickItem::componentComplete(); - - for (QQuickShapePath *p : d->sp) - connect(p, SIGNAL(shapePathChanged()), this, SLOT(_q_shapePathChanged())); - - d->_q_shapePathChanged(); -} - -void QQuickShape::updatePolish() -{ - Q_D(QQuickShape); - - const int currentEffectRefCount = d->extra.isAllocated() ? d->extra->recursiveEffectRefCount : 0; - if (!d->spChanged && currentEffectRefCount <= d->effectRefCount) - return; - - d->spChanged = false; - d->effectRefCount = currentEffectRefCount; - - if (!d->renderer) { - d->createRenderer(); - if (!d->renderer) - return; - emit rendererChanged(); - } - - // endSync() is where expensive calculations may happen (or get kicked off - // on worker threads), depending on the backend. Therefore do this only - // when the item is visible. - if (isVisible() || d->effectRefCount > 0) - d->sync(); - - update(); -} - -void QQuickShape::itemChange(ItemChange change, const ItemChangeData &data) -{ - Q_D(QQuickShape); - - // sync may have been deferred; do it now if the item became visible - if (change == ItemVisibleHasChanged && data.boolValue) - d->_q_shapePathChanged(); - - QQuickItem::itemChange(change, data); -} - -QSGNode *QQuickShape::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) -{ - // Called on the render thread, with the gui thread blocked. We can now - // safely access gui thread data. - - Q_D(QQuickShape); - if (d->renderer) { - if (!node) - node = d->createNode(); - d->renderer->updateNode(); - } - return node; -} - -// the renderer object lives on the gui thread -void QQuickShapePrivate::createRenderer() -{ - Q_Q(QQuickShape); - QSGRendererInterface *ri = q->window()->rendererInterface(); - if (!ri) - return; - - switch (ri->graphicsApi()) { -#if QT_CONFIG(opengl) - case QSGRendererInterface::OpenGL: - if (enableVendorExts && QQuickShapeNvprRenderNode::isSupported()) { - rendererType = QQuickShape::NvprRenderer; - renderer = new QQuickShapeNvprRenderer; - } else { - rendererType = QQuickShape::GeometryRenderer; - renderer = new QQuickShapeGenericRenderer(q); - } - break; -#endif - case QSGRendererInterface::Software: - rendererType = QQuickShape::SoftwareRenderer; - renderer = new QQuickShapeSoftwareRenderer; - break; - default: - qWarning("No path backend for this graphics API yet"); - break; - } -} - -// the node lives on the render thread -QSGNode *QQuickShapePrivate::createNode() -{ - Q_Q(QQuickShape); - QSGNode *node = nullptr; - if (!q->window()) - return node; - QSGRendererInterface *ri = q->window()->rendererInterface(); - if (!ri) - return node; - - switch (ri->graphicsApi()) { -#if QT_CONFIG(opengl) - case QSGRendererInterface::OpenGL: - if (enableVendorExts && QQuickShapeNvprRenderNode::isSupported()) { - node = new QQuickShapeNvprRenderNode; - static_cast(renderer)->setNode( - static_cast(node)); - } else { - node = new QQuickShapeGenericNode; - static_cast(renderer)->setRootNode( - static_cast(node)); - } - break; -#endif - case QSGRendererInterface::Software: - node = new QQuickShapeSoftwareRenderNode(q); - static_cast(renderer)->setNode( - static_cast(node)); - break; - default: - qWarning("No path backend for this graphics API yet"); - break; - } - - return node; -} - -void QQuickShapePrivate::asyncShapeReady(void *data) -{ - QQuickShapePrivate *self = static_cast(data); - self->setStatus(QQuickShape::Ready); - if (self->syncTimingActive) - qDebug("[Shape %p] [%d] [dirty=0x%x] async update took %lld ms", - self->q_func(), self->syncTimeCounter, self->syncTimingTotalDirty, self->syncTimer.elapsed()); -} - -void QQuickShapePrivate::sync() -{ - syncTimingTotalDirty = 0; - syncTimingActive = QQSHAPE_LOG_TIME_DIRTY_SYNC().isDebugEnabled(); - if (syncTimingActive) - syncTimer.start(); - - const bool useAsync = async && renderer->flags().testFlag(QQuickAbstractPathRenderer::SupportsAsync); - if (useAsync) { - setStatus(QQuickShape::Processing); - renderer->setAsyncCallback(asyncShapeReady, this); - } - - const int count = sp.count(); - renderer->beginSync(count); - - for (int i = 0; i < count; ++i) { - QQuickShapePath *p = sp[i]; - int &dirty(QQuickShapePathPrivate::get(p)->dirty); - syncTimingTotalDirty |= dirty; - - if (dirty & QQuickShapePathPrivate::DirtyPath) - renderer->setPath(i, p); - if (dirty & QQuickShapePathPrivate::DirtyStrokeColor) - renderer->setStrokeColor(i, p->strokeColor()); - if (dirty & QQuickShapePathPrivate::DirtyStrokeWidth) - renderer->setStrokeWidth(i, p->strokeWidth()); - if (dirty & QQuickShapePathPrivate::DirtyFillColor) - renderer->setFillColor(i, p->fillColor()); - if (dirty & QQuickShapePathPrivate::DirtyFillRule) - renderer->setFillRule(i, p->fillRule()); - if (dirty & QQuickShapePathPrivate::DirtyStyle) { - renderer->setJoinStyle(i, p->joinStyle(), p->miterLimit()); - renderer->setCapStyle(i, p->capStyle()); - } - if (dirty & QQuickShapePathPrivate::DirtyDash) - renderer->setStrokeStyle(i, p->strokeStyle(), p->dashOffset(), p->dashPattern()); - if (dirty & QQuickShapePathPrivate::DirtyFillGradient) - renderer->setFillGradient(i, p->fillGradient()); - - dirty = 0; - } - - if (syncTimingTotalDirty) - ++syncTimeCounter; - else - syncTimingActive = false; - - renderer->endSync(useAsync); - - if (!useAsync) { - setStatus(QQuickShape::Ready); - if (syncTimingActive) - qDebug("[Shape %p] [%d] [dirty=0x%x] update took %lld ms", - q_func(), syncTimeCounter, syncTimingTotalDirty, syncTimer.elapsed()); - } -} - -// ***** gradient support ***** - -/*! - \qmltype ShapeGradient - \instantiates QQuickShapeGradient - \inqmlmodule QtQuick.Shapes - \ingroup qtquick-paths - \ingroup qtquick-views - \inherits Gradient - \brief Base type of Shape fill gradients. - \since 5.10 - - This is an abstract base class for gradients like LinearGradient and - cannot be created directly. It extends \l Gradient with properties like the - spread mode. - */ - -QQuickShapeGradient::QQuickShapeGradient(QObject *parent) - : QQuickGradient(parent), - m_spread(PadSpread) -{ -} - -/*! - \qmlproperty enumeration QtQuick.Shapes::ShapeGradient::spread - - Specifies how the area outside the gradient area should be filled. The - default value is \c ShapeGradient.PadSpread. - - \value ShapeGradient.PadSpread - The area is filled with the closest stop color. - - \value ShapeGradient.RepeatSpread - The gradient is repeated outside the gradient area. - - \value ShapeGradient.ReflectSpread - The gradient is reflected outside the gradient area. - */ - -QQuickShapeGradient::SpreadMode QQuickShapeGradient::spread() const -{ - return m_spread; -} - -void QQuickShapeGradient::setSpread(SpreadMode mode) -{ - if (m_spread != mode) { - m_spread = mode; - emit spreadChanged(); - emit updated(); - } -} - -/*! - \qmltype LinearGradient - \instantiates QQuickShapeLinearGradient - \inqmlmodule QtQuick.Shapes - \ingroup qtquick-paths - \ingroup qtquick-views - \inherits ShapeGradient - \brief Linear gradient. - \since 5.10 - - Linear gradients interpolate colors between start and end points in Shape - items. Outside these points the gradient is either padded, reflected or - repeated depending on the spread type. - - \note LinearGradient is only supported in combination with Shape items. It - is not compatible with \l Rectangle, as that only supports \l Gradient. - - \sa QLinearGradient - */ - -QQuickShapeLinearGradient::QQuickShapeLinearGradient(QObject *parent) - : QQuickShapeGradient(parent) -{ -} - -/*! - \qmlproperty real QtQuick.Shapes::LinearGradient::x1 - \qmlproperty real QtQuick.Shapes::LinearGradient::y1 - \qmlproperty real QtQuick.Shapes::LinearGradient::x2 - \qmlproperty real QtQuick.Shapes::LinearGradient::y2 - - These properties define the start and end points between which color - interpolation occurs. By default both points are set to (0, 0). - */ - -qreal QQuickShapeLinearGradient::x1() const -{ - return m_start.x(); -} - -void QQuickShapeLinearGradient::setX1(qreal v) -{ - if (m_start.x() != v) { - m_start.setX(v); - emit x1Changed(); - emit updated(); - } -} - -qreal QQuickShapeLinearGradient::y1() const -{ - return m_start.y(); -} - -void QQuickShapeLinearGradient::setY1(qreal v) -{ - if (m_start.y() != v) { - m_start.setY(v); - emit y1Changed(); - emit updated(); - } -} - -qreal QQuickShapeLinearGradient::x2() const -{ - return m_end.x(); -} - -void QQuickShapeLinearGradient::setX2(qreal v) -{ - if (m_end.x() != v) { - m_end.setX(v); - emit x2Changed(); - emit updated(); - } -} - -qreal QQuickShapeLinearGradient::y2() const -{ - return m_end.y(); -} - -void QQuickShapeLinearGradient::setY2(qreal v) -{ - if (m_end.y() != v) { - m_end.setY(v); - emit y2Changed(); - emit updated(); - } -} - -/*! - \qmltype RadialGradient - \instantiates QQuickShapeRadialGradient - \inqmlmodule QtQuick.Shapes - \ingroup qtquick-paths - \ingroup qtquick-views - \inherits ShapeGradient - \brief Radial gradient. - \since 5.10 - - Radial gradients interpolate colors between a focal circle and a center - circle in Shape items. Points outside the cone defined by the two circles - will be transparent. - - Outside the end points the gradient is either padded, reflected or repeated - depending on the spread type. - - Below is an example of a simple radial gradient. Here the colors are - interpolated between the specified point and the end points on a circle - specified by the radius: - - \code - fillGradient: RadialGradient { - centerX: 50; centerY: 50 - centerRadius: 100 - focalX: centerX; focalY: centerY - GradientStop { position: 0; color: "blue" } - GradientStop { position: 0.2; color: "green" } - GradientStop { position: 0.4; color: "red" } - GradientStop { position: 0.6; color: "yellow" } - GradientStop { position: 1; color: "cyan" } - } - \endcode - - \image shape-radial-gradient.png - - Extended radial gradients, where a separate focal circle is specified, are - also supported. - - \note RadialGradient is only supported in combination with Shape items. It - is not compatible with \l Rectangle, as that only supports \l Gradient. - - \sa QRadialGradient - */ - -QQuickShapeRadialGradient::QQuickShapeRadialGradient(QObject *parent) - : QQuickShapeGradient(parent) -{ -} - -/*! - \qmlproperty real QtQuick.Shapes::RadialGradient::centerX - \qmlproperty real QtQuick.Shapes::RadialGradient::centerY - \qmlproperty real QtQuick.Shapes::RadialGradient::focalX - \qmlproperty real QtQuick.Shapes::RadialGradient::focalY - - These properties define the center and focal points. To specify a simple - radial gradient, set focalX and focalY to the value of centerX and - centerY, respectively. - */ - -qreal QQuickShapeRadialGradient::centerX() const -{ - return m_centerPoint.x(); -} - -void QQuickShapeRadialGradient::setCenterX(qreal v) -{ - if (m_centerPoint.x() != v) { - m_centerPoint.setX(v); - emit centerXChanged(); - emit updated(); - } -} - -qreal QQuickShapeRadialGradient::centerY() const -{ - return m_centerPoint.y(); -} - -void QQuickShapeRadialGradient::setCenterY(qreal v) -{ - if (m_centerPoint.y() != v) { - m_centerPoint.setY(v); - emit centerYChanged(); - emit updated(); - } -} - -/*! - \qmlproperty real QtQuick.Shapes::RadialGradient::centerRadius - \qmlproperty real QtQuick.Shapes::RadialGradient::focalRadius - - These properties define the center and focal radius. For simple radial - gradients, focalRadius should be set to \c 0 (the default value). - */ - -qreal QQuickShapeRadialGradient::centerRadius() const -{ - return m_centerRadius; -} - -void QQuickShapeRadialGradient::setCenterRadius(qreal v) -{ - if (m_centerRadius != v) { - m_centerRadius = v; - emit centerRadiusChanged(); - emit updated(); - } -} - -qreal QQuickShapeRadialGradient::focalX() const -{ - return m_focalPoint.x(); -} - -void QQuickShapeRadialGradient::setFocalX(qreal v) -{ - if (m_focalPoint.x() != v) { - m_focalPoint.setX(v); - emit focalXChanged(); - emit updated(); - } -} - -qreal QQuickShapeRadialGradient::focalY() const -{ - return m_focalPoint.y(); -} - -void QQuickShapeRadialGradient::setFocalY(qreal v) -{ - if (m_focalPoint.y() != v) { - m_focalPoint.setY(v); - emit focalYChanged(); - emit updated(); - } -} - -qreal QQuickShapeRadialGradient::focalRadius() const -{ - return m_focalRadius; -} - -void QQuickShapeRadialGradient::setFocalRadius(qreal v) -{ - if (m_focalRadius != v) { - m_focalRadius = v; - emit focalRadiusChanged(); - emit updated(); - } -} - -/*! - \qmltype ConicalGradient - \instantiates QQuickShapeConicalGradient - \inqmlmodule QtQuick.Shapes - \ingroup qtquick-paths - \ingroup qtquick-views - \inherits ShapeGradient - \brief Conical gradient. - \since 5.10 - - Conical gradients interpolate colors counter-clockwise around a center - point in Shape items. - - \note The \l{ShapeGradient::spread}{spread mode} setting has no effect for - conical gradients. - - \note ConicalGradient is only supported in combination with Shape items. It - is not compatible with \l Rectangle, as that only supports \l Gradient. - - \sa QConicalGradient - */ - -QQuickShapeConicalGradient::QQuickShapeConicalGradient(QObject *parent) - : QQuickShapeGradient(parent) -{ -} - -/*! - \qmlproperty real QtQuick.Shapes::ConicalGradient::centerX - \qmlproperty real QtQuick.Shapes::ConicalGradient::centerY - - These properties define the center point of the conical gradient. - */ - -qreal QQuickShapeConicalGradient::centerX() const -{ - return m_centerPoint.x(); -} - -void QQuickShapeConicalGradient::setCenterX(qreal v) -{ - if (m_centerPoint.x() != v) { - m_centerPoint.setX(v); - emit centerXChanged(); - emit updated(); - } -} - -qreal QQuickShapeConicalGradient::centerY() const -{ - return m_centerPoint.y(); -} - -void QQuickShapeConicalGradient::setCenterY(qreal v) -{ - if (m_centerPoint.y() != v) { - m_centerPoint.setY(v); - emit centerYChanged(); - emit updated(); - } -} - -/*! - \qmlproperty real QtQuick.Shapes::ConicalGradient::angle - - This property defines the start angle for the conical gradient. The value - is in degrees (0-360). - */ - -qreal QQuickShapeConicalGradient::angle() const -{ - return m_angle; -} - -void QQuickShapeConicalGradient::setAngle(qreal v) -{ - if (m_angle != v) { - m_angle = v; - emit angleChanged(); - emit updated(); - } -} - -#if QT_CONFIG(opengl) - -// contexts sharing with each other get the same cache instance -class QQuickShapeGradientCacheWrapper -{ -public: - QQuickShapeGradientCache *get(QOpenGLContext *context) - { - return m_resource.value(context); - } - -private: - QOpenGLMultiGroupSharedResource m_resource; -}; - -QQuickShapeGradientCache *QQuickShapeGradientCache::currentCache() -{ - static QQuickShapeGradientCacheWrapper qt_path_gradient_caches; - return qt_path_gradient_caches.get(QOpenGLContext::currentContext()); -} - -// let QOpenGLContext manage the lifetime of the cached textures -QQuickShapeGradientCache::~QQuickShapeGradientCache() -{ - m_cache.clear(); -} - -void QQuickShapeGradientCache::invalidateResource() -{ - m_cache.clear(); -} - -void QQuickShapeGradientCache::freeResource(QOpenGLContext *) -{ - qDeleteAll(m_cache); - m_cache.clear(); -} - -static void generateGradientColorTable(const QQuickShapeGradientCache::Key &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 *QQuickShapeGradientCache::get(const Key &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 QQuickShapeGradient::PadSpread: - tx->setHorizontalWrapMode(QSGTexture::ClampToEdge); - tx->setVerticalWrapMode(QSGTexture::ClampToEdge); - break; - case QQuickShapeGradient::RepeatSpread: - tx->setHorizontalWrapMode(QSGTexture::Repeat); - tx->setVerticalWrapMode(QSGTexture::Repeat); - break; - case QQuickShapeGradient::ReflectSpread: - tx->setHorizontalWrapMode(QSGTexture::MirroredRepeat); - tx->setVerticalWrapMode(QSGTexture::MirroredRepeat); - break; - default: - qWarning("Unknown gradient spread mode %d", grad.spread); - break; - } - tx->setFiltering(QSGTexture::Linear); - m_cache[grad] = tx; - } - return tx; -} - -#endif // QT_CONFIG(opengl) - -QT_END_NAMESPACE - -#include "moc_qquickshape_p.cpp" diff --git a/src/imports/shapes/qquickshape_p.h b/src/imports/shapes/qquickshape_p.h deleted file mode 100644 index 1dfeaf9228..0000000000 --- a/src/imports/shapes/qquickshape_p.h +++ /dev/null @@ -1,376 +0,0 @@ -/**************************************************************************** -** -** 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 QQUICKSHAPE_P_H -#define QQUICKSHAPE_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 -#include -#include - -QT_BEGIN_NAMESPACE - -class QQuickShapePathPrivate; -class QQuickShapePrivate; - -class QQuickShapeGradient : public QQuickGradient -{ - Q_OBJECT - Q_PROPERTY(SpreadMode spread READ spread WRITE setSpread NOTIFY spreadChanged) - Q_CLASSINFO("DefaultProperty", "stops") - -public: - enum SpreadMode { - PadSpread, - RepeatSpread, - ReflectSpread - }; - Q_ENUM(SpreadMode) - - QQuickShapeGradient(QObject *parent = nullptr); - - SpreadMode spread() const; - void setSpread(SpreadMode mode); - -signals: - void spreadChanged(); - -private: - SpreadMode m_spread; -}; - -class QQuickShapeLinearGradient : public QQuickShapeGradient -{ - 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: - QQuickShapeLinearGradient(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 QQuickShapeRadialGradient : public QQuickShapeGradient -{ - Q_OBJECT - Q_PROPERTY(qreal centerX READ centerX WRITE setCenterX NOTIFY centerXChanged) - Q_PROPERTY(qreal centerY READ centerY WRITE setCenterY NOTIFY centerYChanged) - Q_PROPERTY(qreal centerRadius READ centerRadius WRITE setCenterRadius NOTIFY centerRadiusChanged) - Q_PROPERTY(qreal focalX READ focalX WRITE setFocalX NOTIFY focalXChanged) - Q_PROPERTY(qreal focalY READ focalY WRITE setFocalY NOTIFY focalYChanged) - Q_PROPERTY(qreal focalRadius READ focalRadius WRITE setFocalRadius NOTIFY focalRadiusChanged) - Q_CLASSINFO("DefaultProperty", "stops") - -public: - QQuickShapeRadialGradient(QObject *parent = nullptr); - - qreal centerX() const; - void setCenterX(qreal v); - - qreal centerY() const; - void setCenterY(qreal v); - - qreal centerRadius() const; - void setCenterRadius(qreal v); - - qreal focalX() const; - void setFocalX(qreal v); - - qreal focalY() const; - void setFocalY(qreal v); - - qreal focalRadius() const; - void setFocalRadius(qreal v); - -signals: - void centerXChanged(); - void centerYChanged(); - void focalXChanged(); - void focalYChanged(); - void centerRadiusChanged(); - void focalRadiusChanged(); - -private: - QPointF m_centerPoint; - QPointF m_focalPoint; - qreal m_centerRadius = 0; - qreal m_focalRadius = 0; -}; - -class QQuickShapeConicalGradient : public QQuickShapeGradient -{ - Q_OBJECT - Q_PROPERTY(qreal centerX READ centerX WRITE setCenterX NOTIFY centerXChanged) - Q_PROPERTY(qreal centerY READ centerY WRITE setCenterY NOTIFY centerYChanged) - Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged) - Q_CLASSINFO("DefaultProperty", "stops") - -public: - QQuickShapeConicalGradient(QObject *parent = nullptr); - - qreal centerX() const; - void setCenterX(qreal v); - - qreal centerY() const; - void setCenterY(qreal v); - - qreal angle() const; - void setAngle(qreal v); - -signals: - void centerXChanged(); - void centerYChanged(); - void angleChanged(); - -private: - QPointF m_centerPoint; - qreal m_angle = 0; -}; - -class QQuickShapePath : public QQuickPath -{ - Q_OBJECT - - 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 dashPattern READ dashPattern WRITE setDashPattern NOTIFY dashPatternChanged) - Q_PROPERTY(QQuickShapeGradient *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) - - QQuickShapePath(QObject *parent = nullptr); - ~QQuickShapePath(); - - 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 dashPattern() const; - void setDashPattern(const QVector &array); - - QQuickShapeGradient *fillGradient() const; - void setFillGradient(QQuickShapeGradient *gradient); - void resetFillGradient(); - -Q_SIGNALS: - void shapePathChanged(); - void strokeColorChanged(); - void strokeWidthChanged(); - void fillColorChanged(); - void fillRuleChanged(); - void joinStyleChanged(); - void miterLimitChanged(); - void capStyleChanged(); - void strokeStyleChanged(); - void dashOffsetChanged(); - void dashPatternChanged(); - -private: - Q_DISABLE_COPY(QQuickShapePath) - Q_DECLARE_PRIVATE(QQuickShapePath) - Q_PRIVATE_SLOT(d_func(), void _q_fillGradientChanged()) -}; - -class QQuickShape : public QQuickItem -{ - Q_OBJECT - Q_PROPERTY(RendererType rendererType READ rendererType NOTIFY rendererChanged) - Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged) - Q_PROPERTY(bool vendorExtensionsEnabled READ vendorExtensionsEnabled WRITE setVendorExtensionsEnabled NOTIFY vendorExtensionsEnabledChanged) - Q_PROPERTY(Status status READ status NOTIFY statusChanged) - Q_PROPERTY(ContainsMode containsMode READ containsMode WRITE setContainsMode NOTIFY containsModeChanged REVISION 11) - Q_PROPERTY(QQmlListProperty data READ data) - Q_CLASSINFO("DefaultProperty", "data") - -public: - enum RendererType { - UnknownRenderer, - GeometryRenderer, - NvprRenderer, - SoftwareRenderer - }; - Q_ENUM(RendererType) - - enum Status { - Null, - Ready, - Processing - }; - Q_ENUM(Status) - - enum ContainsMode { - BoundingRectContains, - FillContains - }; - Q_ENUM(ContainsMode) - - QQuickShape(QQuickItem *parent = nullptr); - ~QQuickShape(); - - RendererType rendererType() const; - - bool asynchronous() const; - void setAsynchronous(bool async); - - bool vendorExtensionsEnabled() const; - void setVendorExtensionsEnabled(bool enable); - - Status status() const; - - ContainsMode containsMode() const; - void setContainsMode(ContainsMode containsMode); - - bool contains(const QPointF &point) const override; - - QQmlListProperty data(); - -protected: - QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override; - void updatePolish() override; - void itemChange(ItemChange change, const ItemChangeData &data) override; - void componentComplete() override; - void classBegin() override; - -Q_SIGNALS: - void rendererChanged(); - void asynchronousChanged(); - void vendorExtensionsEnabledChanged(); - void statusChanged(); - Q_REVISION(11) void containsModeChanged(); - -private: - Q_DISABLE_COPY(QQuickShape) - Q_DECLARE_PRIVATE(QQuickShape) - Q_PRIVATE_SLOT(d_func(), void _q_shapePathChanged()) -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QQuickShape) - -#endif // QQUICKSHAPE_P_H diff --git a/src/imports/shapes/qquickshape_p_p.h b/src/imports/shapes/qquickshape_p_p.h deleted file mode 100644 index ef2775885e..0000000000 --- a/src/imports/shapes/qquickshape_p_p.h +++ /dev/null @@ -1,231 +0,0 @@ -/**************************************************************************** -** -** 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 QQUICKSHAPE_P_P_H -#define QQUICKSHAPE_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 "qquickshape_p.h" -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QSGPlainTexture; - -class QQuickAbstractPathRenderer -{ -public: - enum Flag { - SupportsAsync = 0x01 - }; - Q_DECLARE_FLAGS(Flags, Flag) - - enum FillGradientType { NoGradient = 0, LinearGradient, RadialGradient, ConicalGradient }; - struct GradientDesc { // can fully describe a linear/radial/conical gradient - QGradientStops stops; - QQuickShapeGradient::SpreadMode spread; - QPointF a; // start (L) or center point (R/C) - QPointF b; // end (L) or focal point (R) - qreal v0; // center radius (R) or start angle (C) - qreal v1; // focal radius (R) - }; - - virtual ~QQuickAbstractPathRenderer() { } - - // Gui thread - virtual void beginSync(int totalCount) = 0; - virtual void endSync(bool async) = 0; - virtual void setAsyncCallback(void (*)(void *), void *) { } - virtual Flags flags() const { return 0; } - virtual void setPath(int index, const QQuickPath *path) = 0; - virtual void setStrokeColor(int index, const QColor &color) = 0; - virtual void setStrokeWidth(int index, qreal w) = 0; - virtual void setFillColor(int index, const QColor &color) = 0; - virtual void setFillRule(int index, QQuickShapePath::FillRule fillRule) = 0; - virtual void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) = 0; - virtual void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) = 0; - virtual void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, - qreal dashOffset, const QVector &dashPattern) = 0; - virtual void setFillGradient(int index, QQuickShapeGradient *gradient) = 0; - - // Render thread, with gui blocked - virtual void updateNode() = 0; -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickAbstractPathRenderer::Flags) - -struct QQuickShapeStrokeFillParams -{ - QQuickShapeStrokeFillParams(); - - QColor strokeColor; - qreal strokeWidth; - QColor fillColor; - QQuickShapePath::FillRule fillRule; - QQuickShapePath::JoinStyle joinStyle; - int miterLimit; - QQuickShapePath::CapStyle capStyle; - QQuickShapePath::StrokeStyle strokeStyle; - qreal dashOffset; - QVector dashPattern; - QQuickShapeGradient *fillGradient; -}; - -class QQuickShapePathPrivate : public QQuickPathPrivate -{ - Q_DECLARE_PUBLIC(QQuickShapePath) - -public: - enum Dirty { - DirtyPath = 0x01, - DirtyStrokeColor = 0x02, - DirtyStrokeWidth = 0x04, - DirtyFillColor = 0x08, - DirtyFillRule = 0x10, - DirtyStyle = 0x20, - DirtyDash = 0x40, - DirtyFillGradient = 0x80, - - DirtyAll = 0xFF - }; - - QQuickShapePathPrivate(); - - void _q_pathChanged(); - void _q_fillGradientChanged(); - - static QQuickShapePathPrivate *get(QQuickShapePath *p) { return p->d_func(); } - - int dirty; - QQuickShapeStrokeFillParams sfp; -}; - -class QQuickShapePrivate : public QQuickItemPrivate -{ - Q_DECLARE_PUBLIC(QQuickShape) - -public: - QQuickShapePrivate(); - ~QQuickShapePrivate(); - - void createRenderer(); - QSGNode *createNode(); - void sync(); - - void _q_shapePathChanged(); - void setStatus(QQuickShape::Status newStatus); - - static QQuickShapePrivate *get(QQuickShape *item) { return item->d_func(); } - - static void asyncShapeReady(void *data); - - int effectRefCount; - QVector sp; - QElapsedTimer syncTimer; - QQuickAbstractPathRenderer *renderer = nullptr; - int syncTimingTotalDirty = 0; - int syncTimeCounter = 0; - QQuickShape::Status status = QQuickShape::Null; - QQuickShape::RendererType rendererType = QQuickShape::UnknownRenderer; - QQuickShape::ContainsMode containsMode = QQuickShape::BoundingRectContains; - bool spChanged = false; - bool async = false; - bool enableVendorExts = true; - bool syncTimingActive = false; -}; - -#if QT_CONFIG(opengl) - -class QQuickShapeGradientCache : public QOpenGLSharedResource -{ -public: - struct Key { - Key(const QGradientStops &stops, QQuickShapeGradient::SpreadMode spread) - : stops(stops), spread(spread) - { } - QGradientStops stops; - QQuickShapeGradient::SpreadMode spread; - bool operator==(const Key &other) const - { - return spread == other.spread && stops == other.stops; - } - }; - - QQuickShapeGradientCache(QOpenGLContext *context) : QOpenGLSharedResource(context->shareGroup()) { } - ~QQuickShapeGradientCache(); - - void invalidateResource() override; - void freeResource(QOpenGLContext *) override; - - QSGTexture *get(const Key &grad); - - static QQuickShapeGradientCache *currentCache(); - -private: - QHash m_cache; -}; - -inline uint qHash(const QQuickShapeGradientCache::Key &v, uint seed = 0) -{ - uint h = seed + v.spread; - for (int i = 0; i < 3 && i < v.stops.count(); ++i) - h += v.stops[i].second.rgba(); - return h; -} - -#endif // QT_CONFIG(opengl) - -QT_END_NAMESPACE - -#endif diff --git a/src/imports/shapes/qquickshapegenericrenderer.cpp b/src/imports/shapes/qquickshapegenericrenderer.cpp deleted file mode 100644 index 8a4785a83a..0000000000 --- a/src/imports/shapes/qquickshapegenericrenderer.cpp +++ /dev/null @@ -1,1007 +0,0 @@ -/**************************************************************************** -** -** 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 "qquickshapegenericrenderer_p.h" -#include -#include -#include - -#if QT_CONFIG(opengl) -#include -#include -#include -#include -#endif - -QT_BEGIN_NAMESPACE - -static const qreal TRI_SCALE = 1; - -struct ColoredVertex // must match QSGGeometry::ColoredPoint2D -{ - float x, y; - QQuickShapeGenericRenderer::Color4ub color; - void set(float nx, float ny, QQuickShapeGenericRenderer::Color4ub ncolor) - { - x = nx; y = ny; color = ncolor; - } -}; - -static inline QQuickShapeGenericRenderer::Color4ub colorToColor4ub(const QColor &c) -{ - QQuickShapeGenericRenderer::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; -} - -QQuickShapeGenericStrokeFillNode::QQuickShapeGenericStrokeFillNode(QQuickWindow *window) - : m_material(nullptr) -{ - setFlag(QSGNode::OwnsGeometry, true); - setGeometry(new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0)); - activateMaterial(window, MatSolidColor); -#ifdef QSG_RUNTIME_DESCRIPTION - qsgnode_set_description(this, QLatin1String("stroke-fill")); -#endif -} - -void QQuickShapeGenericStrokeFillNode::activateMaterial(QQuickWindow *window, 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. - m_material.reset(QQuickShapeGenericMaterialFactory::createVertexColor(window)); - break; - case MatLinearGradient: - m_material.reset(QQuickShapeGenericMaterialFactory::createLinearGradient(window, this)); - break; - case MatRadialGradient: - m_material.reset(QQuickShapeGenericMaterialFactory::createRadialGradient(window, this)); - break; - case MatConicalGradient: - m_material.reset(QQuickShapeGenericMaterialFactory::createConicalGradient(window, this)); - break; - default: - qWarning("Unknown material %d", m); - return; - } - - if (material() != m_material.data()) - setMaterial(m_material.data()); -} - -static bool q_supportsElementIndexUint(QSGRendererInterface::GraphicsApi api) -{ - static bool elementIndexUint = true; -#if QT_CONFIG(opengl) - if (api == QSGRendererInterface::OpenGL) { - static bool elementIndexUintChecked = false; - if (!elementIndexUintChecked) { - elementIndexUintChecked = true; - QOpenGLContext *context = QOpenGLContext::currentContext(); - QScopedPointer dummyContext; - QScopedPointer dummySurface; - bool ok = true; - if (!context) { - dummyContext.reset(new QOpenGLContext); - dummyContext->create(); - context = dummyContext.data(); - dummySurface.reset(new QOffscreenSurface); - dummySurface->setFormat(context->format()); - dummySurface->create(); - ok = context->makeCurrent(dummySurface.data()); - } - if (ok) { - elementIndexUint = static_cast(context->functions())->hasOpenGLExtension( - QOpenGLExtensions::ElementIndexUint); - } - } - } -#else - Q_UNUSED(api); -#endif - return elementIndexUint; -} - -QQuickShapeGenericRenderer::~QQuickShapeGenericRenderer() -{ - for (ShapePathData &d : m_sp) { - if (d.pendingFill) - d.pendingFill->orphaned = true; - if (d.pendingStroke) - d.pendingStroke->orphaned = true; - } -} - -// sync, and so triangulation too, happens on the gui thread -// - except when async is set, in which case triangulation is moved to worker threads - -void QQuickShapeGenericRenderer::beginSync(int totalCount) -{ - if (m_sp.count() != totalCount) { - m_sp.resize(totalCount); - m_accDirty |= DirtyList; - } - for (ShapePathData &d : m_sp) - d.syncDirty = 0; -} - -void QQuickShapeGenericRenderer::setPath(int index, const QQuickPath *path) -{ - ShapePathData &d(m_sp[index]); - d.path = path ? path->path() : QPainterPath(); - d.syncDirty |= DirtyFillGeom | DirtyStrokeGeom; -} - -void QQuickShapeGenericRenderer::setStrokeColor(int index, const QColor &color) -{ - ShapePathData &d(m_sp[index]); - d.strokeColor = colorToColor4ub(color); - d.syncDirty |= DirtyColor; -} - -void QQuickShapeGenericRenderer::setStrokeWidth(int index, qreal w) -{ - ShapePathData &d(m_sp[index]); - d.strokeWidth = w; - if (w >= 0.0f) - d.pen.setWidthF(w); - d.syncDirty |= DirtyStrokeGeom; -} - -void QQuickShapeGenericRenderer::setFillColor(int index, const QColor &color) -{ - ShapePathData &d(m_sp[index]); - d.fillColor = colorToColor4ub(color); - d.syncDirty |= DirtyColor; -} - -void QQuickShapeGenericRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule) -{ - ShapePathData &d(m_sp[index]); - d.fillRule = Qt::FillRule(fillRule); - d.syncDirty |= DirtyFillGeom; -} - -void QQuickShapeGenericRenderer::setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) -{ - ShapePathData &d(m_sp[index]); - d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle)); - d.pen.setMiterLimit(miterLimit); - d.syncDirty |= DirtyStrokeGeom; -} - -void QQuickShapeGenericRenderer::setCapStyle(int index, QQuickShapePath::CapStyle capStyle) -{ - ShapePathData &d(m_sp[index]); - d.pen.setCapStyle(Qt::PenCapStyle(capStyle)); - d.syncDirty |= DirtyStrokeGeom; -} - -void QQuickShapeGenericRenderer::setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, - qreal dashOffset, const QVector &dashPattern) -{ - ShapePathData &d(m_sp[index]); - d.pen.setStyle(Qt::PenStyle(strokeStyle)); - if (strokeStyle == QQuickShapePath::DashLine) { - d.pen.setDashPattern(dashPattern); - d.pen.setDashOffset(dashOffset); - } - d.syncDirty |= DirtyStrokeGeom; -} - -void QQuickShapeGenericRenderer::setFillGradient(int index, QQuickShapeGradient *gradient) -{ - ShapePathData &d(m_sp[index]); - if (gradient) { - d.fillGradient.stops = gradient->gradientStops(); // sorted - d.fillGradient.spread = gradient->spread(); - if (QQuickShapeLinearGradient *g = qobject_cast(gradient)) { - d.fillGradientActive = LinearGradient; - d.fillGradient.a = QPointF(g->x1(), g->y1()); - d.fillGradient.b = QPointF(g->x2(), g->y2()); - } else if (QQuickShapeRadialGradient *g = qobject_cast(gradient)) { - d.fillGradientActive = RadialGradient; - d.fillGradient.a = QPointF(g->centerX(), g->centerY()); - d.fillGradient.b = QPointF(g->focalX(), g->focalY()); - d.fillGradient.v0 = g->centerRadius(); - d.fillGradient.v1 = g->focalRadius(); - } else if (QQuickShapeConicalGradient *g = qobject_cast(gradient)) { - d.fillGradientActive = ConicalGradient; - d.fillGradient.a = QPointF(g->centerX(), g->centerY()); - d.fillGradient.v0 = g->angle(); - } else { - Q_UNREACHABLE(); - } - } else { - d.fillGradientActive = NoGradient; - } - d.syncDirty |= DirtyFillGradient; -} - -void QQuickShapeFillRunnable::run() -{ - QQuickShapeGenericRenderer::triangulateFill(path, fillColor, &fillVertices, &fillIndices, &indexType, supportsElementIndexUint); - emit done(this); -} - -void QQuickShapeStrokeRunnable::run() -{ - QQuickShapeGenericRenderer::triangulateStroke(path, pen, strokeColor, &strokeVertices, clipSize); - emit done(this); -} - -void QQuickShapeGenericRenderer::setAsyncCallback(void (*callback)(void *), void *data) -{ - m_asyncCallback = callback; - m_asyncCallbackData = data; -} - -static QThreadPool *pathWorkThreadPool = nullptr; - -static void deletePathWorkThreadPool() -{ - delete pathWorkThreadPool; - pathWorkThreadPool = nullptr; -} - -void QQuickShapeGenericRenderer::endSync(bool async) -{ - bool didKickOffAsync = false; - - for (int i = 0; i < m_sp.count(); ++i) { - ShapePathData &d(m_sp[i]); - if (!d.syncDirty) - continue; - - m_accDirty |= d.syncDirty; - - // 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 updateNode() - // on the render thread (with the gui thread blocked). For our purposes - // here syncDirty is still required since geometry regeneration must only - // happen when there was an actual change in this particular sync round. - d.effectiveDirty |= d.syncDirty; - - if (d.path.isEmpty()) { - d.fillVertices.clear(); - d.fillIndices.clear(); - d.strokeVertices.clear(); - continue; - } - - if (async && !pathWorkThreadPool) { - qAddPostRoutine(deletePathWorkThreadPool); - pathWorkThreadPool = new QThreadPool; - const int idealCount = QThread::idealThreadCount(); - pathWorkThreadPool->setMaxThreadCount(idealCount > 0 ? idealCount * 2 : 4); - } - - if ((d.syncDirty & DirtyFillGeom) && d.fillColor.a) { - d.path.setFillRule(d.fillRule); - if (m_api == QSGRendererInterface::Unknown) - m_api = m_item->window()->rendererInterface()->graphicsApi(); - if (async) { - QQuickShapeFillRunnable *r = new QQuickShapeFillRunnable; - r->setAutoDelete(false); - if (d.pendingFill) - d.pendingFill->orphaned = true; - d.pendingFill = r; - r->path = d.path; - r->fillColor = d.fillColor; - r->supportsElementIndexUint = q_supportsElementIndexUint(m_api); - // Unlikely in practice but in theory m_sp could be - // resized. Therefore, capture 'i' instead of 'd'. - QObject::connect(r, &QQuickShapeFillRunnable::done, qApp, [this, i](QQuickShapeFillRunnable *r) { - // Bail out when orphaned (meaning either another run was - // started after this one, or the renderer got destroyed). - if (!r->orphaned && i < m_sp.count()) { - ShapePathData &d(m_sp[i]); - d.fillVertices = r->fillVertices; - d.fillIndices = r->fillIndices; - d.indexType = r->indexType; - d.pendingFill = nullptr; - d.effectiveDirty |= DirtyFillGeom; - maybeUpdateAsyncItem(); - } - r->deleteLater(); - }); - didKickOffAsync = true; - pathWorkThreadPool->start(r); - } else { - triangulateFill(d.path, d.fillColor, &d.fillVertices, &d.fillIndices, &d.indexType, q_supportsElementIndexUint(m_api)); - } - } - - if ((d.syncDirty & DirtyStrokeGeom) && d.strokeWidth >= 0.0f && d.strokeColor.a) { - if (async) { - QQuickShapeStrokeRunnable *r = new QQuickShapeStrokeRunnable; - r->setAutoDelete(false); - if (d.pendingStroke) - d.pendingStroke->orphaned = true; - d.pendingStroke = r; - r->path = d.path; - r->pen = d.pen; - r->strokeColor = d.strokeColor; - r->clipSize = QSize(m_item->width(), m_item->height()); - QObject::connect(r, &QQuickShapeStrokeRunnable::done, qApp, [this, i](QQuickShapeStrokeRunnable *r) { - if (!r->orphaned && i < m_sp.count()) { - ShapePathData &d(m_sp[i]); - d.strokeVertices = r->strokeVertices; - d.pendingStroke = nullptr; - d.effectiveDirty |= DirtyStrokeGeom; - maybeUpdateAsyncItem(); - } - r->deleteLater(); - }); - didKickOffAsync = true; - pathWorkThreadPool->start(r); - } else { - triangulateStroke(d.path, d.pen, d.strokeColor, &d.strokeVertices, - QSize(m_item->width(), m_item->height())); - } - } - } - - if (!didKickOffAsync && async && m_asyncCallback) - m_asyncCallback(m_asyncCallbackData); -} - -void QQuickShapeGenericRenderer::maybeUpdateAsyncItem() -{ - for (const ShapePathData &d : qAsConst(m_sp)) { - if (d.pendingFill || d.pendingStroke) - return; - } - m_accDirty |= DirtyFillGeom | DirtyStrokeGeom; - m_item->update(); - if (m_asyncCallback) - m_asyncCallback(m_asyncCallbackData); -} - -// the stroke/fill triangulation functions may be invoked either on the gui -// thread or some worker thread and must thus be self-contained. -void QQuickShapeGenericRenderer::triangulateFill(const QPainterPath &path, - const Color4ub &fillColor, - VertexContainerType *fillVertices, - IndexContainerType *fillIndices, - QSGGeometry::Type *indexType, - bool supportsElementIndexUint) -{ - const QVectorPath &vp = qtVectorPathForPath(path); - - QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(TRI_SCALE, TRI_SCALE), 1, supportsElementIndexUint); - const int vertexCount = ts.vertices.count() / 2; // just a qreal vector with x,y hence the / 2 - fillVertices->resize(vertexCount); - ColoredVertex *vdst = reinterpret_cast(fillVertices->data()); - const qreal *vsrc = ts.vertices.constData(); - for (int i = 0; i < vertexCount; ++i) - vdst[i].set(vsrc[i * 2] / TRI_SCALE, vsrc[i * 2 + 1] / TRI_SCALE, fillColor); - - size_t indexByteSize; - if (ts.indices.type() == QVertexIndexVector::UnsignedShort) { - *indexType = QSGGeometry::UnsignedShortType; - // fillIndices is still QVector. Just resize to N/2 and pack - // the N quint16s into it. - fillIndices->resize(ts.indices.size() / 2); - indexByteSize = ts.indices.size() * sizeof(quint16); - } else { - *indexType = QSGGeometry::UnsignedIntType; - fillIndices->resize(ts.indices.size()); - indexByteSize = ts.indices.size() * sizeof(quint32); - } - memcpy(fillIndices->data(), ts.indices.data(), indexByteSize); -} - -void QQuickShapeGenericRenderer::triangulateStroke(const QPainterPath &path, - const QPen &pen, - const Color4ub &strokeColor, - VertexContainerType *strokeVertices, - const QSize &clipSize) -{ - const QVectorPath &vp = qtVectorPathForPath(path); - const QRectF clip(QPointF(0, 0), clipSize); - const qreal inverseScale = 1.0 / TRI_SCALE; - - QTriangulatingStroker stroker; - stroker.setInvScale(inverseScale); - - if (pen.style() == Qt::SolidLine) { - stroker.process(vp, pen, clip, nullptr); - } else { - QDashedStrokeProcessor dashStroker; - dashStroker.setInvScale(inverseScale); - dashStroker.process(vp, pen, clip, nullptr); - QVectorPath dashStroke(dashStroker.points(), dashStroker.elementCount(), - dashStroker.elementTypes(), 0); - stroker.process(dashStroke, pen, clip, nullptr); - } - - if (!stroker.vertexCount()) { - strokeVertices->clear(); - return; - } - - const int vertexCount = stroker.vertexCount() / 2; // just a float vector with x,y hence the / 2 - strokeVertices->resize(vertexCount); - ColoredVertex *vdst = reinterpret_cast(strokeVertices->data()); - const float *vsrc = stroker.vertices(); - for (int i = 0; i < vertexCount; ++i) - vdst[i].set(vsrc[i * 2], vsrc[i * 2 + 1], strokeColor); -} - -void QQuickShapeGenericRenderer::setRootNode(QQuickShapeGenericNode *node) -{ - if (m_rootNode != node) { - m_rootNode = node; - m_accDirty |= DirtyList; - } -} - -// on the render thread with gui blocked -void QQuickShapeGenericRenderer::updateNode() -{ - if (!m_rootNode || !m_accDirty) - return; - -// [ m_rootNode ] -// / / / -// #0 [ fill ] [ stroke ] [ next ] -// / / | -// #1 [ fill ] [ stroke ] [ next ] -// / / | -// #2 [ fill ] [ stroke ] [ next ] -// ... -// ... - - QQuickShapeGenericNode **nodePtr = &m_rootNode; - QQuickShapeGenericNode *prevNode = nullptr; - - for (ShapePathData &d : m_sp) { - if (!*nodePtr) { - Q_ASSERT(prevNode); - *nodePtr = new QQuickShapeGenericNode; - prevNode->m_next = *nodePtr; - prevNode->appendChildNode(*nodePtr); - } - - QQuickShapeGenericNode *node = *nodePtr; - - if (m_accDirty & DirtyList) - d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient; - - if (!d.effectiveDirty) { - prevNode = node; - nodePtr = &node->m_next; - continue; - } - - if (d.fillColor.a == 0) { - delete node->m_fillNode; - node->m_fillNode = nullptr; - } else if (!node->m_fillNode) { - node->m_fillNode = new QQuickShapeGenericStrokeFillNode(m_item->window()); - if (node->m_strokeNode) - node->removeChildNode(node->m_strokeNode); - node->appendChildNode(node->m_fillNode); - if (node->m_strokeNode) - node->appendChildNode(node->m_strokeNode); - d.effectiveDirty |= DirtyFillGeom; - } - - if (d.strokeWidth < 0.0f || d.strokeColor.a == 0) { - delete node->m_strokeNode; - node->m_strokeNode = nullptr; - } else if (!node->m_strokeNode) { - node->m_strokeNode = new QQuickShapeGenericStrokeFillNode(m_item->window()); - node->appendChildNode(node->m_strokeNode); - d.effectiveDirty |= DirtyStrokeGeom; - } - - updateFillNode(&d, node); - updateStrokeNode(&d, node); - - d.effectiveDirty = 0; - - prevNode = node; - nodePtr = &node->m_next; - } - - if (*nodePtr && prevNode) { - prevNode->removeChildNode(*nodePtr); - delete *nodePtr; - *nodePtr = nullptr; - } - - m_accDirty = 0; -} - -void QQuickShapeGenericRenderer::updateShadowDataInNode(ShapePathData *d, QQuickShapeGenericStrokeFillNode *n) -{ - if (d->fillGradientActive) { - if (d->effectiveDirty & DirtyFillGradient) - n->m_fillGradient = d->fillGradient; - } -} - -void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node) -{ - if (!node->m_fillNode) - return; - if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient))) - return; - - // Make a copy of the data that will be accessed by the material on - // the render thread. This must be done even when we bail out below. - QQuickShapeGenericStrokeFillNode *n = node->m_fillNode; - updateShadowDataInNode(d, n); - - QSGGeometry *g = n->geometry(); - if (d->fillVertices.isEmpty()) { - if (g->vertexCount() || g->indexCount()) { - g->allocate(0, 0); - n->markDirty(QSGNode::DirtyGeometry); - } - return; - } - - if (d->fillGradientActive) { - QQuickShapeGenericStrokeFillNode::Material gradMat; - switch (d->fillGradientActive) { - case LinearGradient: - gradMat = QQuickShapeGenericStrokeFillNode::MatLinearGradient; - break; - case RadialGradient: - gradMat = QQuickShapeGenericStrokeFillNode::MatRadialGradient; - break; - case ConicalGradient: - gradMat = QQuickShapeGenericStrokeFillNode::MatConicalGradient; - break; - default: - Q_UNREACHABLE(); - return; - } - n->activateMaterial(m_item->window(), gradMat); - if (d->effectiveDirty & DirtyFillGradient) { - // 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 (!(d->effectiveDirty & DirtyFillGeom)) - return; - } - } else { - n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatSolidColor); - // fast path for updating only color values when no change in vertex positions - if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom)) { - ColoredVertex *vdst = reinterpret_cast(g->vertexData()); - for (int i = 0; i < g->vertexCount(); ++i) - vdst[i].set(vdst[i].x, vdst[i].y, d->fillColor); - n->markDirty(QSGNode::DirtyGeometry); - return; - } - } - - const int indexCount = d->indexType == QSGGeometry::UnsignedShortType - ? d->fillIndices.count() * 2 : d->fillIndices.count(); - if (g->indexType() != d->indexType) { - g = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), - d->fillVertices.count(), indexCount, d->indexType); - n->setGeometry(g); - } else { - g->allocate(d->fillVertices.count(), indexCount); - } - g->setDrawingMode(QSGGeometry::DrawTriangles); - memcpy(g->vertexData(), d->fillVertices.constData(), g->vertexCount() * g->sizeOfVertex()); - memcpy(g->indexData(), d->fillIndices.constData(), g->indexCount() * g->sizeOfIndex()); - - n->markDirty(QSGNode::DirtyGeometry); -} - -void QQuickShapeGenericRenderer::updateStrokeNode(ShapePathData *d, QQuickShapeGenericNode *node) -{ - if (!node->m_strokeNode) - return; - if (!(d->effectiveDirty & (DirtyStrokeGeom | DirtyColor))) - return; - - QQuickShapeGenericStrokeFillNode *n = node->m_strokeNode; - QSGGeometry *g = n->geometry(); - if (d->strokeVertices.isEmpty()) { - if (g->vertexCount() || g->indexCount()) { - g->allocate(0, 0); - n->markDirty(QSGNode::DirtyGeometry); - } - return; - } - - n->markDirty(QSGNode::DirtyGeometry); - - // Async loading runs update once, bails out above, then updates again once - // ready. Set the material dirty then. This is in-line with fill where the - // first activateMaterial() achieves the same. - if (!g->vertexCount()) - n->markDirty(QSGNode::DirtyMaterial); - - if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyStrokeGeom)) { - ColoredVertex *vdst = reinterpret_cast(g->vertexData()); - for (int i = 0; i < g->vertexCount(); ++i) - vdst[i].set(vdst[i].x, vdst[i].y, d->strokeColor); - return; - } - - g->allocate(d->strokeVertices.count(), 0); - g->setDrawingMode(QSGGeometry::DrawTriangleStrip); - memcpy(g->vertexData(), d->strokeVertices.constData(), g->vertexCount() * g->sizeOfVertex()); -} - -QSGMaterial *QQuickShapeGenericMaterialFactory::createVertexColor(QQuickWindow *window) -{ - QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); - -#if QT_CONFIG(opengl) - if (api == QSGRendererInterface::OpenGL) - return new QSGVertexColorMaterial; -#endif - - qWarning("Vertex-color material: Unsupported graphics API %d", api); - return nullptr; -} - -QSGMaterial *QQuickShapeGenericMaterialFactory::createLinearGradient(QQuickWindow *window, - QQuickShapeGenericStrokeFillNode *node) -{ - QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); - -#if QT_CONFIG(opengl) - if (api == QSGRendererInterface::OpenGL) - return new QQuickShapeLinearGradientMaterial(node); -#else - Q_UNUSED(node); -#endif - - qWarning("Linear gradient material: Unsupported graphics API %d", api); - return nullptr; -} - -QSGMaterial *QQuickShapeGenericMaterialFactory::createRadialGradient(QQuickWindow *window, - QQuickShapeGenericStrokeFillNode *node) -{ - QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); - -#if QT_CONFIG(opengl) - if (api == QSGRendererInterface::OpenGL) - return new QQuickShapeRadialGradientMaterial(node); -#else - Q_UNUSED(node); -#endif - - qWarning("Radial gradient material: Unsupported graphics API %d", api); - return nullptr; -} - -QSGMaterial *QQuickShapeGenericMaterialFactory::createConicalGradient(QQuickWindow *window, - QQuickShapeGenericStrokeFillNode *node) -{ - QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); - -#if QT_CONFIG(opengl) - if (api == QSGRendererInterface::OpenGL) - return new QQuickShapeConicalGradientMaterial(node); -#else - Q_UNUSED(node); -#endif - - qWarning("Conical gradient material: Unsupported graphics API %d", api); - return nullptr; -} - -#if QT_CONFIG(opengl) - -QSGMaterialType QQuickShapeLinearGradientShader::type; - -QQuickShapeLinearGradientShader::QQuickShapeLinearGradientShader() -{ - setShaderSourceFile(QOpenGLShader::Vertex, - QStringLiteral(":/qt-project.org/shapes/shaders/lineargradient.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, - QStringLiteral(":/qt-project.org/shapes/shaders/lineargradient.frag")); -} - -void QQuickShapeLinearGradientShader::initialize() -{ - m_opacityLoc = program()->uniformLocation("opacity"); - m_matrixLoc = program()->uniformLocation("matrix"); - m_gradStartLoc = program()->uniformLocation("gradStart"); - m_gradEndLoc = program()->uniformLocation("gradEnd"); -} - -void QQuickShapeLinearGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *) -{ - QQuickShapeLinearGradientMaterial *m = static_cast(mat); - - if (state.isOpacityDirty()) - program()->setUniformValue(m_opacityLoc, state.opacity()); - - if (state.isMatrixDirty()) - program()->setUniformValue(m_matrixLoc, state.combinedMatrix()); - - QQuickShapeGenericStrokeFillNode *node = m->node(); - program()->setUniformValue(m_gradStartLoc, QVector2D(node->m_fillGradient.a)); - program()->setUniformValue(m_gradEndLoc, QVector2D(node->m_fillGradient.b)); - - const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); - QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); - tx->bind(); -} - -char const *const *QQuickShapeLinearGradientShader::attributeNames() const -{ - static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr }; - return attr; -} - -int QQuickShapeLinearGradientMaterial::compare(const QSGMaterial *other) const -{ - Q_ASSERT(other && type() == other->type()); - const QQuickShapeLinearGradientMaterial *m = static_cast(other); - - QQuickShapeGenericStrokeFillNode *a = node(); - QQuickShapeGenericStrokeFillNode *b = m->node(); - Q_ASSERT(a && b); - if (a == b) - return 0; - - const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient; - const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient; - - if (int d = ga->spread - gb->spread) - return d; - - if (int d = ga->a.x() - gb->a.x()) - return d; - if (int d = ga->a.y() - gb->a.y()) - return d; - if (int d = ga->b.x() - gb->b.x()) - return d; - if (int d = ga->b.y() - gb->b.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; -} - -QSGMaterialType QQuickShapeRadialGradientShader::type; - -QQuickShapeRadialGradientShader::QQuickShapeRadialGradientShader() -{ - setShaderSourceFile(QOpenGLShader::Vertex, - QStringLiteral(":/qt-project.org/shapes/shaders/radialgradient.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, - QStringLiteral(":/qt-project.org/shapes/shaders/radialgradient.frag")); -} - -void QQuickShapeRadialGradientShader::initialize() -{ - QOpenGLShaderProgram *prog = program(); - m_opacityLoc = prog->uniformLocation("opacity"); - m_matrixLoc = prog->uniformLocation("matrix"); - m_translationPointLoc = prog->uniformLocation("translationPoint"); - m_focalToCenterLoc = prog->uniformLocation("focalToCenter"); - m_centerRadiusLoc = prog->uniformLocation("centerRadius"); - m_focalRadiusLoc = prog->uniformLocation("focalRadius"); -} - -void QQuickShapeRadialGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *) -{ - QQuickShapeRadialGradientMaterial *m = static_cast(mat); - - if (state.isOpacityDirty()) - program()->setUniformValue(m_opacityLoc, state.opacity()); - - if (state.isMatrixDirty()) - program()->setUniformValue(m_matrixLoc, state.combinedMatrix()); - - QQuickShapeGenericStrokeFillNode *node = m->node(); - - const QPointF centerPoint = node->m_fillGradient.a; - const QPointF focalPoint = node->m_fillGradient.b; - const QPointF focalToCenter = centerPoint - focalPoint; - const GLfloat centerRadius = node->m_fillGradient.v0; - const GLfloat focalRadius = node->m_fillGradient.v1; - - program()->setUniformValue(m_translationPointLoc, focalPoint); - program()->setUniformValue(m_centerRadiusLoc, centerRadius); - program()->setUniformValue(m_focalRadiusLoc, focalRadius); - program()->setUniformValue(m_focalToCenterLoc, focalToCenter); - - const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); - QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); - tx->bind(); -} - -char const *const *QQuickShapeRadialGradientShader::attributeNames() const -{ - static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr }; - return attr; -} - -int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const -{ - Q_ASSERT(other && type() == other->type()); - const QQuickShapeRadialGradientMaterial *m = static_cast(other); - - QQuickShapeGenericStrokeFillNode *a = node(); - QQuickShapeGenericStrokeFillNode *b = m->node(); - Q_ASSERT(a && b); - if (a == b) - return 0; - - const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient; - const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient; - - if (int d = ga->spread - gb->spread) - return d; - - if (int d = ga->a.x() - gb->a.x()) - return d; - if (int d = ga->a.y() - gb->a.y()) - return d; - if (int d = ga->b.x() - gb->b.x()) - return d; - if (int d = ga->b.y() - gb->b.y()) - return d; - - if (int d = ga->v0 - gb->v0) - return d; - if (int d = ga->v1 - gb->v1) - 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; -} - -QSGMaterialType QQuickShapeConicalGradientShader::type; - -QQuickShapeConicalGradientShader::QQuickShapeConicalGradientShader() -{ - setShaderSourceFile(QOpenGLShader::Vertex, - QStringLiteral(":/qt-project.org/shapes/shaders/conicalgradient.vert")); - setShaderSourceFile(QOpenGLShader::Fragment, - QStringLiteral(":/qt-project.org/shapes/shaders/conicalgradient.frag")); -} - -void QQuickShapeConicalGradientShader::initialize() -{ - QOpenGLShaderProgram *prog = program(); - m_opacityLoc = prog->uniformLocation("opacity"); - m_matrixLoc = prog->uniformLocation("matrix"); - m_angleLoc = prog->uniformLocation("angle"); - m_translationPointLoc = prog->uniformLocation("translationPoint"); -} - -void QQuickShapeConicalGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *) -{ - QQuickShapeConicalGradientMaterial *m = static_cast(mat); - - if (state.isOpacityDirty()) - program()->setUniformValue(m_opacityLoc, state.opacity()); - - if (state.isMatrixDirty()) - program()->setUniformValue(m_matrixLoc, state.combinedMatrix()); - - QQuickShapeGenericStrokeFillNode *node = m->node(); - - const QPointF centerPoint = node->m_fillGradient.a; - const GLfloat angle = -qDegreesToRadians(node->m_fillGradient.v0); - - program()->setUniformValue(m_angleLoc, angle); - program()->setUniformValue(m_translationPointLoc, centerPoint); - - const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, QQuickShapeGradient::RepeatSpread); - QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); - tx->bind(); -} - -char const *const *QQuickShapeConicalGradientShader::attributeNames() const -{ - static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr }; - return attr; -} - -int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const -{ - Q_ASSERT(other && type() == other->type()); - const QQuickShapeConicalGradientMaterial *m = static_cast(other); - - QQuickShapeGenericStrokeFillNode *a = node(); - QQuickShapeGenericStrokeFillNode *b = m->node(); - Q_ASSERT(a && b); - if (a == b) - return 0; - - const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient; - const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient; - - if (int d = ga->a.x() - gb->a.x()) - return d; - if (int d = ga->a.y() - gb->a.y()) - return d; - - if (int d = ga->v0 - gb->v0) - 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_CONFIG(opengl) - -QT_END_NAMESPACE diff --git a/src/imports/shapes/qquickshapegenericrenderer_p.h b/src/imports/shapes/qquickshapegenericrenderer_p.h deleted file mode 100644 index 11070ae7dc..0000000000 --- a/src/imports/shapes/qquickshapegenericrenderer_p.h +++ /dev/null @@ -1,392 +0,0 @@ -/**************************************************************************** -** -** 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 QQUICKSHAPEGENERICRENDERER_P_H -#define QQUICKSHAPEGENERICRENDERER_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 "qquickshape_p_p.h" -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QQuickShapeGenericNode; -class QQuickShapeGenericStrokeFillNode; -class QQuickShapeFillRunnable; -class QQuickShapeStrokeRunnable; - -class QQuickShapeGenericRenderer : public QQuickAbstractPathRenderer -{ -public: - enum Dirty { - DirtyFillGeom = 0x01, - DirtyStrokeGeom = 0x02, - DirtyColor = 0x04, - DirtyFillGradient = 0x08, - DirtyList = 0x10 // only for accDirty - }; - - QQuickShapeGenericRenderer(QQuickItem *item) - : m_item(item), - m_api(QSGRendererInterface::Unknown), - m_rootNode(nullptr), - m_accDirty(0), - m_asyncCallback(nullptr), - m_asyncCallbackData(nullptr) - { } - ~QQuickShapeGenericRenderer(); - - void beginSync(int totalCount) override; - void setPath(int index, const QQuickPath *path) override; - void setStrokeColor(int index, const QColor &color) override; - void setStrokeWidth(int index, qreal w) override; - void setFillColor(int index, const QColor &color) override; - void setFillRule(int index, QQuickShapePath::FillRule fillRule) override; - void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override; - void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override; - void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, - qreal dashOffset, const QVector &dashPattern) override; - void setFillGradient(int index, QQuickShapeGradient *gradient) override; - void endSync(bool async) override; - void setAsyncCallback(void (*)(void *), void *) override; - Flags flags() const override { return SupportsAsync; } - - void updateNode() override; - - void setRootNode(QQuickShapeGenericNode *node); - - struct Color4ub { unsigned char r, g, b, a; }; - typedef QVector VertexContainerType; - typedef QVector IndexContainerType; - - static void triangulateFill(const QPainterPath &path, - const Color4ub &fillColor, - VertexContainerType *fillVertices, - IndexContainerType *fillIndices, - QSGGeometry::Type *indexType, - bool supportsElementIndexUint); - static void triangulateStroke(const QPainterPath &path, - const QPen &pen, - const Color4ub &strokeColor, - VertexContainerType *strokeVertices, - const QSize &clipSize); - -private: - void maybeUpdateAsyncItem(); - - struct ShapePathData { - float strokeWidth; - QPen pen; - Color4ub strokeColor; - Color4ub fillColor; - Qt::FillRule fillRule; - QPainterPath path; - FillGradientType fillGradientActive; - GradientDesc fillGradient; - VertexContainerType fillVertices; - IndexContainerType fillIndices; - QSGGeometry::Type indexType; - VertexContainerType strokeVertices; - int syncDirty; - int effectiveDirty = 0; - QQuickShapeFillRunnable *pendingFill = nullptr; - QQuickShapeStrokeRunnable *pendingStroke = nullptr; - }; - - void updateShadowDataInNode(ShapePathData *d, QQuickShapeGenericStrokeFillNode *n); - void updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node); - void updateStrokeNode(ShapePathData *d, QQuickShapeGenericNode *node); - - QQuickItem *m_item; - QSGRendererInterface::GraphicsApi m_api; - QQuickShapeGenericNode *m_rootNode; - QVector m_sp; - int m_accDirty; - void (*m_asyncCallback)(void *); - void *m_asyncCallbackData; -}; - -class QQuickShapeFillRunnable : public QObject, public QRunnable -{ - Q_OBJECT - -public: - void run() override; - - bool orphaned = false; - - // input - QPainterPath path; - QQuickShapeGenericRenderer::Color4ub fillColor; - bool supportsElementIndexUint; - - // output - QQuickShapeGenericRenderer::VertexContainerType fillVertices; - QQuickShapeGenericRenderer::IndexContainerType fillIndices; - QSGGeometry::Type indexType; - -Q_SIGNALS: - void done(QQuickShapeFillRunnable *self); -}; - -class QQuickShapeStrokeRunnable : public QObject, public QRunnable -{ - Q_OBJECT - -public: - void run() override; - - bool orphaned = false; - - // input - QPainterPath path; - QPen pen; - QQuickShapeGenericRenderer::Color4ub strokeColor; - QSize clipSize; - - // output - QQuickShapeGenericRenderer::VertexContainerType strokeVertices; - -Q_SIGNALS: - void done(QQuickShapeStrokeRunnable *self); -}; - -class QQuickShapeGenericStrokeFillNode : public QSGGeometryNode -{ -public: - QQuickShapeGenericStrokeFillNode(QQuickWindow *window); - - enum Material { - MatSolidColor, - MatLinearGradient, - MatRadialGradient, - MatConicalGradient - }; - - void activateMaterial(QQuickWindow *window, Material m); - - // shadow data for custom materials - QQuickAbstractPathRenderer::GradientDesc m_fillGradient; - -private: - QScopedPointer m_material; - - friend class QQuickShapeGenericRenderer; -}; - -class QQuickShapeGenericNode : public QSGNode -{ -public: - QQuickShapeGenericStrokeFillNode *m_fillNode = nullptr; - QQuickShapeGenericStrokeFillNode *m_strokeNode = nullptr; - QQuickShapeGenericNode *m_next = nullptr; -}; - -class QQuickShapeGenericMaterialFactory -{ -public: - static QSGMaterial *createVertexColor(QQuickWindow *window); - static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); - static QSGMaterial *createRadialGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); - static QSGMaterial *createConicalGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); -}; - -#if QT_CONFIG(opengl) - -class QQuickShapeLinearGradientShader : public QSGMaterialShader -{ -public: - QQuickShapeLinearGradientShader(); - - 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 = -1; - int m_matrixLoc = -1; - int m_gradStartLoc = -1; - int m_gradEndLoc = -1; -}; - -class QQuickShapeLinearGradientMaterial : public QSGMaterial -{ -public: - QQuickShapeLinearGradientMaterial(QQuickShapeGenericStrokeFillNode *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 Shape-space coordinate and so no modifications - // are welcome. - setFlag(Blending | RequiresFullMatrix); - } - - QSGMaterialType *type() const override - { - return &QQuickShapeLinearGradientShader::type; - } - - int compare(const QSGMaterial *other) const override; - - QSGMaterialShader *createShader() const override - { - return new QQuickShapeLinearGradientShader; - } - - QQuickShapeGenericStrokeFillNode *node() const { return m_node; } - -private: - QQuickShapeGenericStrokeFillNode *m_node; -}; - -class QQuickShapeRadialGradientShader : public QSGMaterialShader -{ -public: - QQuickShapeRadialGradientShader(); - - 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 = -1; - int m_matrixLoc = -1; - int m_translationPointLoc = -1; - int m_focalToCenterLoc = -1; - int m_centerRadiusLoc = -1; - int m_focalRadiusLoc = -1; -}; - -class QQuickShapeRadialGradientMaterial : public QSGMaterial -{ -public: - QQuickShapeRadialGradientMaterial(QQuickShapeGenericStrokeFillNode *node) - : m_node(node) - { - setFlag(Blending | RequiresFullMatrix); - } - - QSGMaterialType *type() const override - { - return &QQuickShapeRadialGradientShader::type; - } - - int compare(const QSGMaterial *other) const override; - - QSGMaterialShader *createShader() const override - { - return new QQuickShapeRadialGradientShader; - } - - QQuickShapeGenericStrokeFillNode *node() const { return m_node; } - -private: - QQuickShapeGenericStrokeFillNode *m_node; -}; - -class QQuickShapeConicalGradientShader : public QSGMaterialShader -{ -public: - QQuickShapeConicalGradientShader(); - - 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 = -1; - int m_matrixLoc = -1; - int m_angleLoc = -1; - int m_translationPointLoc = -1; -}; - -class QQuickShapeConicalGradientMaterial : public QSGMaterial -{ -public: - QQuickShapeConicalGradientMaterial(QQuickShapeGenericStrokeFillNode *node) - : m_node(node) - { - setFlag(Blending | RequiresFullMatrix); - } - - QSGMaterialType *type() const override - { - return &QQuickShapeConicalGradientShader::type; - } - - int compare(const QSGMaterial *other) const override; - - QSGMaterialShader *createShader() const override - { - return new QQuickShapeConicalGradientShader; - } - - QQuickShapeGenericStrokeFillNode *node() const { return m_node; } - -private: - QQuickShapeGenericStrokeFillNode *m_node; -}; - -#endif // QT_CONFIG(opengl) - -QT_END_NAMESPACE - -#endif // QQUICKSHAPEGENERICRENDERER_P_H diff --git a/src/imports/shapes/qquickshapenvprrenderer.cpp b/src/imports/shapes/qquickshapenvprrenderer.cpp deleted file mode 100644 index 51af0d8961..0000000000 --- a/src/imports/shapes/qquickshapenvprrenderer.cpp +++ /dev/null @@ -1,1001 +0,0 @@ -/**************************************************************************** -** -** 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 "qquickshapenvprrenderer_p.h" -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -void QQuickShapeNvprRenderer::beginSync(int totalCount) -{ - if (m_sp.count() != totalCount) { - m_sp.resize(totalCount); - m_accDirty |= DirtyList; - } -} - -void QQuickShapeNvprRenderer::setPath(int index, const QQuickPath *path) -{ - ShapePathGuiData &d(m_sp[index]); - convertPath(path, &d); - d.dirty |= DirtyPath; - m_accDirty |= DirtyPath; -} - -void QQuickShapeNvprRenderer::setStrokeColor(int index, const QColor &color) -{ - ShapePathGuiData &d(m_sp[index]); - d.strokeColor = color; - d.dirty |= DirtyStyle; - m_accDirty |= DirtyStyle; -} - -void QQuickShapeNvprRenderer::setStrokeWidth(int index, qreal w) -{ - ShapePathGuiData &d(m_sp[index]); - d.strokeWidth = w; - d.dirty |= DirtyStyle; - m_accDirty |= DirtyStyle; -} - -void QQuickShapeNvprRenderer::setFillColor(int index, const QColor &color) -{ - ShapePathGuiData &d(m_sp[index]); - d.fillColor = color; - d.dirty |= DirtyStyle; - m_accDirty |= DirtyStyle; -} - -void QQuickShapeNvprRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule) -{ - ShapePathGuiData &d(m_sp[index]); - d.fillRule = fillRule; - d.dirty |= DirtyFillRule; - m_accDirty |= DirtyFillRule; -} - -void QQuickShapeNvprRenderer::setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) -{ - ShapePathGuiData &d(m_sp[index]); - d.joinStyle = joinStyle; - d.miterLimit = miterLimit; - d.dirty |= DirtyStyle; - m_accDirty |= DirtyStyle; -} - -void QQuickShapeNvprRenderer::setCapStyle(int index, QQuickShapePath::CapStyle capStyle) -{ - ShapePathGuiData &d(m_sp[index]); - d.capStyle = capStyle; - d.dirty |= DirtyStyle; - m_accDirty |= DirtyStyle; -} - -void QQuickShapeNvprRenderer::setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, - qreal dashOffset, const QVector &dashPattern) -{ - ShapePathGuiData &d(m_sp[index]); - d.dashActive = strokeStyle == QQuickShapePath::DashLine; - d.dashOffset = dashOffset; - d.dashPattern = dashPattern; - d.dirty |= DirtyDash; - m_accDirty |= DirtyDash; -} - -void QQuickShapeNvprRenderer::setFillGradient(int index, QQuickShapeGradient *gradient) -{ - ShapePathGuiData &d(m_sp[index]); - if (gradient) { - d.fillGradient.stops = gradient->gradientStops(); // sorted - d.fillGradient.spread = gradient->spread(); - if (QQuickShapeLinearGradient *g = qobject_cast(gradient)) { - d.fillGradientActive = LinearGradient; - d.fillGradient.a = QPointF(g->x1(), g->y1()); - d.fillGradient.b = QPointF(g->x2(), g->y2()); - } else if (QQuickShapeRadialGradient *g = qobject_cast(gradient)) { - d.fillGradientActive = RadialGradient; - d.fillGradient.a = QPointF(g->centerX(), g->centerY()); - d.fillGradient.b = QPointF(g->focalX(), g->focalY()); - d.fillGradient.v0 = g->centerRadius(); - d.fillGradient.v1 = g->focalRadius(); - } else if (QQuickShapeConicalGradient *g = qobject_cast(gradient)) { - d.fillGradientActive = ConicalGradient; - d.fillGradient.a = QPointF(g->centerX(), g->centerY()); - d.fillGradient.v0 = g->angle(); - } else { - Q_UNREACHABLE(); - } - } else { - d.fillGradientActive = NoGradient; - } - d.dirty |= DirtyFillGradient; - m_accDirty |= DirtyFillGradient; -} - -void QQuickShapeNvprRenderer::endSync(bool) -{ -} - -void QQuickShapeNvprRenderer::setNode(QQuickShapeNvprRenderNode *node) -{ - if (m_node != node) { - m_node = node; - m_accDirty |= DirtyList; - } -} - -QDebug operator<<(QDebug debug, const QQuickShapeNvprRenderer::NvprPath &path) -{ - QDebugStateSaver saver(debug); - debug.space().noquote(); - if (!path.str.isEmpty()) { - debug << "Path with SVG string" << path.str; - return debug; - } - 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 *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 *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 *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 *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 QQuickShapeNvprRenderer::convertPath(const QQuickPath *path, ShapePathGuiData *d) -{ - d->path = NvprPath(); - if (!path) - return; - - const QList &pp(QQuickPathPrivate::get(path)->_pathElements); - if (pp.isEmpty()) - return; - - QPointF startPos(path->startX(), path->startY()); - QPointF pos(startPos); - if (!qFuzzyIsNull(pos.x()) || !qFuzzyIsNull(pos.y())) { - d->path.cmd.append(GL_MOVE_TO_NV); - d->path.coord.append(pos.x()); - d->path.coord.append(pos.y()); - } - - for (QQuickPathElement *e : pp) { - if (QQuickPathMove *o = qobject_cast(e)) { - d->path.cmd.append(GL_MOVE_TO_NV); - appendCoords(&d->path.coord, o, &pos); - startPos = pos; - } else if (QQuickPathLine *o = qobject_cast(e)) { - d->path.cmd.append(GL_LINE_TO_NV); - appendCoords(&d->path.coord, o, &pos); - } else if (QQuickPathQuad *o = qobject_cast(e)) { - d->path.cmd.append(GL_QUADRATIC_CURVE_TO_NV); - appendControlCoords(&d->path.coord, o, pos); - appendCoords(&d->path.coord, o, &pos); - } else if (QQuickPathCubic *o = qobject_cast(e)) { - d->path.cmd.append(GL_CUBIC_CURVE_TO_NV); - appendControl1Coords(&d->path.coord, o, pos); - appendControl2Coords(&d->path.coord, o, pos); - appendCoords(&d->path.coord, o, &pos); - } else if (QQuickPathArc *o = qobject_cast(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; - d->path.cmd.append(cmd); - d->path.coord.append(o->radiusX()); - d->path.coord.append(o->radiusY()); - d->path.coord.append(o->xAxisRotation()); - appendCoords(&d->path.coord, o, &pos); - } else if (QQuickPathSvg *o = qobject_cast(e)) { - // PathSvg cannot be combined with other elements. But take at - // least startX and startY into account. - if (d->path.str.isEmpty()) - d->path.str = QString(QStringLiteral("M %1 %2 ")).arg(pos.x()).arg(pos.y()).toUtf8(); - d->path.str.append(o->path().toUtf8()); - } else if (QQuickPathAngleArc *o = qobject_cast(e)) { - QRectF rect(o->centerX() - o->radiusX(), o->centerY() - o->radiusY(), o->radiusX() * 2, o->radiusY() * 2); - QPointF startPoint; - QPointF endPoint; - qt_find_ellipse_coords(rect, o->startAngle(), -o->sweepAngle(), &startPoint, &endPoint); - - // get to our starting position - if (o->moveToStart()) - d->path.cmd.append(GL_MOVE_TO_NV); - else - d->path.cmd.append(GL_LINE_TO_NV); // ### should we check if startPoint == pos? - d->path.coord.append(startPoint.x()); - d->path.coord.append(startPoint.y()); - - const bool sweepFlag = o->sweepAngle() > 0; // maps to CCW, not a typo - d->path.cmd.append(qAbs(o->sweepAngle()) > 180.0 - ? (sweepFlag ? GL_LARGE_CCW_ARC_TO_NV : GL_LARGE_CW_ARC_TO_NV) - : (sweepFlag ? GL_SMALL_CCW_ARC_TO_NV : GL_SMALL_CW_ARC_TO_NV)); - d->path.coord.append(o->radiusX()); - d->path.coord.append(o->radiusY()); - d->path.coord.append(0); // xAxisRotation - d->path.coord.append(endPoint.x()); - d->path.coord.append(endPoint.y()); - pos = endPoint; - } else { - qWarning() << "Shape/NVPR: unsupported Path element" << e; - } - } - - // For compatibility with QTriangulatingStroker. SVG and others would not - // implicitly close the path when end_pos == start_pos (start_pos being the - // last moveTo pos); that would still need an explicit 'z' or similar. We - // don't have an explicit close command, so just fake a close when the - // positions match. - if (pos == startPos) - d->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 QQuickShapeNvprRenderer::updateNode() -{ - // Called on the render thread with gui blocked -> update the node with its - // own copy of all relevant data. - - if (!m_accDirty) - return; - - const int count = m_sp.count(); - const bool listChanged = m_accDirty & DirtyList; - if (listChanged) - m_node->m_sp.resize(count); - - for (int i = 0; i < count; ++i) { - ShapePathGuiData &src(m_sp[i]); - QQuickShapeNvprRenderNode::ShapePathRenderData &dst(m_node->m_sp[i]); - - int dirty = src.dirty; - src.dirty = 0; - if (listChanged) - dirty |= DirtyPath | DirtyStyle | DirtyFillRule | DirtyDash | DirtyFillGradient; - - // updateNode() can be called several times with different dirty - // states before render() gets invoked. So accumulate. - dst.dirty |= dirty; - - if (dirty & DirtyPath) - dst.source = src.path; - - if (dirty & DirtyStyle) { - dst.strokeWidth = src.strokeWidth; - dst.strokeColor = qsg_premultiply(src.strokeColor, 1.0f); - dst.fillColor = qsg_premultiply(src.fillColor, 1.0f); - switch (src.joinStyle) { - case QQuickShapePath::MiterJoin: - dst.joinStyle = GL_MITER_TRUNCATE_NV; - break; - case QQuickShapePath::BevelJoin: - dst.joinStyle = GL_BEVEL_NV; - break; - case QQuickShapePath::RoundJoin: - dst.joinStyle = GL_ROUND_NV; - break; - default: - Q_UNREACHABLE(); - } - dst.miterLimit = src.miterLimit; - switch (src.capStyle) { - case QQuickShapePath::FlatCap: - dst.capStyle = GL_FLAT; - break; - case QQuickShapePath::SquareCap: - dst.capStyle = GL_SQUARE_NV; - break; - case QQuickShapePath::RoundCap: - dst.capStyle = GL_ROUND_NV; - break; - default: - Q_UNREACHABLE(); - } - } - - if (dirty & DirtyFillRule) { - switch (src.fillRule) { - case QQuickShapePath::OddEvenFill: - dst.fillRule = GL_INVERT; - break; - case QQuickShapePath::WindingFill: - dst.fillRule = GL_COUNT_UP_NV; - break; - default: - Q_UNREACHABLE(); - } - } - - if (dirty & DirtyDash) { - // Multiply by strokeWidth because the Shape API follows QPen - // meaning the input dash pattern and dash offset here are in width units. - dst.dashOffset = src.dashOffset * src.strokeWidth; - if (src.dashActive) { - if (src.dashPattern.isEmpty()) { - // default values for DashLine as defined in qpen.cpp - dst.dashPattern.resize(2); - dst.dashPattern[0] = 4 * src.strokeWidth; // dash - dst.dashPattern[1] = 2 * src.strokeWidth; // space - } else { - dst.dashPattern.resize(src.dashPattern.count()); - for (int i = 0; i < src.dashPattern.count(); ++i) - dst.dashPattern[i] = GLfloat(src.dashPattern[i]) * src.strokeWidth; - - // QPen expects a dash pattern of even length and so should we - if (src.dashPattern.count() % 2 != 0) { - qWarning("QQuickShapeNvprRenderNode: dash pattern not of even length"); - dst.dashPattern << src.strokeWidth; - } - } - } else { - dst.dashPattern.clear(); - } - } - - if (dirty & DirtyFillGradient) { - dst.fillGradientActive = src.fillGradientActive; - if (src.fillGradientActive) - dst.fillGradient = src.fillGradient; - } - } - - m_node->markDirty(QSGNode::DirtyMaterial); - m_accDirty = 0; -} - -bool QQuickShapeNvprRenderNode::nvprInited = false; -QQuickNvprFunctions QQuickShapeNvprRenderNode::nvpr; -QQuickNvprMaterialManager QQuickShapeNvprRenderNode::mtlmgr; - -QQuickShapeNvprRenderNode::~QQuickShapeNvprRenderNode() -{ - releaseResources(); -} - -void QQuickShapeNvprRenderNode::releaseResources() -{ - for (ShapePathRenderData &d : m_sp) { - if (d.path) { - nvpr.deletePaths(d.path, 1); - d.path = 0; - } - if (d.fallbackFbo) { - delete d.fallbackFbo; - d.fallbackFbo = nullptr; - } - } - - m_fallbackBlitter.destroy(); -} - -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 if (m == MatRadialGradient) { - static const char *fragSrc = - "#version 310 es\n" - "precision highp float;\n" - "uniform sampler2D gradTab;\n" - "uniform float opacity;\n" - "uniform vec2 focalToCenter;\n" - "uniform float centerRadius;\n" - "uniform float focalRadius;\n" - "uniform vec2 translationPoint;\n" - "layout(location = 0) in vec2 uv;\n" - "out vec4 fragColor;\n" - "void main() {\n" - " vec2 coord = uv - translationPoint;\n" - " float rd = centerRadius - focalRadius;\n" - " float b = 2.0 * (rd * focalRadius + dot(coord, focalToCenter));\n" - " float fmp2_m_radius2 = -focalToCenter.x * focalToCenter.x - focalToCenter.y * focalToCenter.y + rd * rd;\n" - " float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2);\n" - " float det = b * b - 4.0 * fmp2_m_radius2 * ((focalRadius * focalRadius) - dot(coord, coord));\n" - " vec4 result = vec4(0.0);\n" - " if (det >= 0.0) {\n" - " float detSqrt = sqrt(det);\n" - " float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2);\n" - " if (focalRadius + w * (centerRadius - focalRadius) >= 0.0)\n" - " result = texture(gradTab, vec2(w, 0.5)) * opacity;\n" - " }\n" - " fragColor = result;\n" - "}\n"; - if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) { - qWarning("NVPR: Failed to create shader pipeline for radial 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, "focalToCenter"); - Q_ASSERT(mtl.uniLoc[2] >= 0); - mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "centerRadius"); - Q_ASSERT(mtl.uniLoc[3] >= 0); - mtl.uniLoc[4] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "focalRadius"); - Q_ASSERT(mtl.uniLoc[4] >= 0); - mtl.uniLoc[5] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "translationPoint"); - Q_ASSERT(mtl.uniLoc[5] >= 0); - } else if (m == MatConicalGradient) { - static const char *fragSrc = - "#version 310 es\n" - "precision highp float;\n" - "#define INVERSE_2PI 0.1591549430918953358\n" - "uniform sampler2D gradTab;\n" - "uniform float opacity;\n" - "uniform float angle;\n" - "uniform vec2 translationPoint;\n" - "layout(location = 0) in vec2 uv;\n" - "out vec4 fragColor;\n" - "void main() {\n" - " vec2 coord = uv - translationPoint;\n" - " float t;\n" - " if (abs(coord.y) == abs(coord.x))\n" - " t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI;\n" - " else\n" - " t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI;\n" - " fragColor = texture(gradTab, vec2(t - floor(t), 0.5)) * opacity;\n" - "}\n"; - if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) { - qWarning("NVPR: Failed to create shader pipeline for conical 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, "angle"); - Q_ASSERT(mtl.uniLoc[2] >= 0); - mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "translationPoint"); - Q_ASSERT(mtl.uniLoc[3] >= 0); - } else { - Q_UNREACHABLE(); - } - } - - f->glBindProgramPipeline(mtl.ppl); - - return &mtl; -} - -void QQuickShapeNvprRenderNode::updatePath(ShapePathRenderData *d) -{ - if (d->dirty & QQuickShapeNvprRenderer::DirtyPath) { - if (!d->path) { - d->path = nvpr.genPaths(1); - Q_ASSERT(d->path != 0); - } - if (d->source.str.isEmpty()) { - nvpr.pathCommands(d->path, d->source.cmd.count(), d->source.cmd.constData(), - d->source.coord.count(), GL_FLOAT, d->source.coord.constData()); - } else { - nvpr.pathString(d->path, GL_PATH_FORMAT_SVG_NV, d->source.str.count(), d->source.str.constData()); - } - } - - if (d->dirty & QQuickShapeNvprRenderer::DirtyStyle) { - nvpr.pathParameterf(d->path, GL_PATH_STROKE_WIDTH_NV, d->strokeWidth); - nvpr.pathParameteri(d->path, GL_PATH_JOIN_STYLE_NV, d->joinStyle); - nvpr.pathParameteri(d->path, GL_PATH_MITER_LIMIT_NV, d->miterLimit); - nvpr.pathParameteri(d->path, GL_PATH_END_CAPS_NV, d->capStyle); - nvpr.pathParameteri(d->path, GL_PATH_DASH_CAPS_NV, d->capStyle); - } - - if (d->dirty & QQuickShapeNvprRenderer::DirtyDash) { - nvpr.pathParameterf(d->path, GL_PATH_DASH_OFFSET_NV, d->dashOffset); - // count == 0 -> no dash - nvpr.pathDashArray(d->path, d->dashPattern.count(), d->dashPattern.constData()); - } - - if (d->dirty) - d->fallbackValid = false; -} - -void QQuickShapeNvprRenderNode::renderStroke(ShapePathRenderData *d, int strokeStencilValue, int writeMask) -{ - QQuickNvprMaterialManager::MaterialDesc *mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid); - f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0], - d->strokeColor.x(), d->strokeColor.y(), d->strokeColor.z(), d->strokeColor.w()); - f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity()); - - nvpr.stencilThenCoverStrokePath(d->path, strokeStencilValue, writeMask, GL_CONVEX_HULL_NV); -} - -void QQuickShapeNvprRenderNode::renderFill(ShapePathRenderData *d) -{ - QQuickNvprMaterialManager::MaterialDesc *mtl = nullptr; - if (d->fillGradientActive) { - QQuickShapeGradient::SpreadMode spread = d->fillGradient.spread; - if (d->fillGradientActive == QQuickAbstractPathRenderer::LinearGradient) { - mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatLinearGradient); - // 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], d->fillGradient.a.x(), d->fillGradient.a.y()); - f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], d->fillGradient.b.x(), d->fillGradient.b.y()); - } else if (d->fillGradientActive == QQuickAbstractPathRenderer::RadialGradient) { - mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatRadialGradient); - // simply drive uv (location 0) with x and y, just like for the linear gradient - GLfloat coeff[6] = { 1, 0, 0, - 0, 1, 0 }; - nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff); - - const QPointF centerPoint = d->fillGradient.a; - const QPointF focalPoint = d->fillGradient.b; - const QPointF focalToCenter = centerPoint - focalPoint; - const GLfloat centerRadius = d->fillGradient.v0; - const GLfloat focalRadius = d->fillGradient.v1; - - f->glProgramUniform2f(mtl->prg, mtl->uniLoc[2], focalToCenter.x(), focalToCenter.y()); - f->glProgramUniform1f(mtl->prg, mtl->uniLoc[3], centerRadius); - f->glProgramUniform1f(mtl->prg, mtl->uniLoc[4], focalRadius); - f->glProgramUniform2f(mtl->prg, mtl->uniLoc[5], focalPoint.x(), focalPoint.y()); - } else if (d->fillGradientActive == QQuickAbstractPathRenderer::ConicalGradient) { - mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatConicalGradient); - // same old - GLfloat coeff[6] = { 1, 0, 0, - 0, 1, 0 }; - nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff); - - const QPointF centerPoint = d->fillGradient.a; - const GLfloat angle = -qDegreesToRadians(d->fillGradient.v0); - - f->glProgramUniform1f(mtl->prg, mtl->uniLoc[2], angle); - f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], centerPoint.x(), centerPoint.y()); - - spread = QQuickShapeGradient::RepeatSpread; - } else { - Q_UNREACHABLE(); - } - const QQuickShapeGradientCache::Key cacheKey(d->fillGradient.stops, spread); - QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); - tx->bind(); - } else { - mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid); - f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0], - d->fillColor.x(), d->fillColor.y(), d->fillColor.z(), d->fillColor.w()); - } - f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity()); - - const int writeMask = 0xFF; - nvpr.stencilThenCoverFillPath(d->path, d->fillRule, writeMask, GL_BOUNDING_BOX_NV); -} - -void QQuickShapeNvprRenderNode::renderOffscreenFill(ShapePathRenderData *d) -{ - if (d->fallbackValid && d->fallbackFbo) - return; - - GLfloat bb[4]; - nvpr.getPathParameterfv(d->path, GL_PATH_STROKE_BOUNDING_BOX_NV, bb); - QSize sz = QSizeF(bb[2] - bb[0] + 1, bb[3] - bb[1] + 1).toSize(); - d->fallbackSize = QSize(qMax(32, sz.width()), qMax(32, sz.height())); - d->fallbackTopLeft = QPointF(bb[0], bb[1]); - - if (d->fallbackFbo && d->fallbackFbo->size() != d->fallbackSize) { - delete d->fallbackFbo; - d->fallbackFbo = nullptr; - } - if (!d->fallbackFbo) - d->fallbackFbo = new QOpenGLFramebufferObject(d->fallbackSize, QOpenGLFramebufferObject::CombinedDepthStencil); - if (!d->fallbackFbo->bind()) - return; - - GLint prevViewport[4]; - f->glGetIntegerv(GL_VIEWPORT, prevViewport); - - f->glViewport(0, 0, d->fallbackSize.width(), d->fallbackSize.height()); - f->glDisable(GL_DEPTH_TEST); - f->glClearColor(0, 0, 0, 0); - f->glClearStencil(0); - f->glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); - f->glStencilFunc(GL_NOTEQUAL, 0, 0xFF); - f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - - QMatrix4x4 mv; - mv.translate(-d->fallbackTopLeft.x(), -d->fallbackTopLeft.y()); - nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, mv.constData()); - QMatrix4x4 proj; - proj.ortho(0, d->fallbackSize.width(), d->fallbackSize.height(), 0, 1, -1); - nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, proj.constData()); - - renderFill(d); - - d->fallbackFbo->release(); - f->glEnable(GL_DEPTH_TEST); - f->glViewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3]); - - d->fallbackValid = true; -} - -void QQuickShapeNvprRenderNode::setupStencilForCover(bool stencilClip, int sv) -{ - if (!stencilClip) { - // 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->glStencilFunc(GL_NOTEQUAL, 0, 0xFF); - f->glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); - } else { - f->glStencilFunc(GL_LESS, sv, 0xFF); // pass if (sv & 0xFF) < (stencil_value & 0xFF) - f->glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // dppass: replace with the original value (clip's stencil ref value) - } -} - -void QQuickShapeNvprRenderNode::render(const RenderState *state) -{ - f = QOpenGLContext::currentContext()->extraFunctions(); - - if (!nvprInited) { - if (!nvpr.create()) { - qWarning("NVPR init failed"); - return; - } - mtlmgr.create(&nvpr); - nvprInited = true; - } - - f->glUseProgram(0); - f->glStencilMask(~0); - f->glEnable(GL_STENCIL_TEST); - - const bool stencilClip = state->stencilEnabled(); - // when true, the stencil buffer already has a clip path with a ref value of sv - const int sv = state->stencilValue(); - const bool hasScissor = state->scissorEnabled(); - - if (hasScissor) { - // scissor rect is already set, just enable scissoring - f->glEnable(GL_SCISSOR_TEST); - } - - // 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); - - bool reloadMatrices = true; - - for (ShapePathRenderData &d : m_sp) { - updatePath(&d); - - const bool hasFill = d.hasFill(); - const bool hasStroke = d.hasStroke(); - - if (hasFill && stencilClip) { - // Fall back to a texture when complex clipping is in use and we have - // to fill. Reconciling glStencilFillPath's and the scenegraph's clip - // stencil semantics has not succeeded so far... - if (hasScissor) - f->glDisable(GL_SCISSOR_TEST); - renderOffscreenFill(&d); - reloadMatrices = true; - if (hasScissor) - f->glEnable(GL_SCISSOR_TEST); - } - - if (reloadMatrices) { - reloadMatrices = false; - nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, matrix()->constData()); - nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, state->projectionMatrix()->constData()); - } - - // Fill! - if (hasFill) { - if (!stencilClip) { - setupStencilForCover(false, 0); - renderFill(&d); - } else { - if (!m_fallbackBlitter.isCreated()) - m_fallbackBlitter.create(); - f->glStencilFunc(GL_EQUAL, sv, 0xFF); - f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); - QMatrix4x4 mv = *matrix(); - mv.translate(d.fallbackTopLeft.x(), d.fallbackTopLeft.y()); - m_fallbackBlitter.texturedQuad(d.fallbackFbo->texture(), d.fallbackFbo->size(), - *state->projectionMatrix(), mv, - inheritedOpacity()); - } - } - - // Stroke! - if (hasStroke) { - const int strokeStencilValue = 0x80; - const int writeMask = 0x80; - - setupStencilForCover(stencilClip, sv); - if (stencilClip) { - // for the stencil step (eff. read mask == 0xFF & ~writeMask) - nvpr.pathStencilFunc(GL_EQUAL, sv, 0xFF); - // With stencilCLip == true the read mask for the stencil test before the stencil step is 0x7F. - // This assumes the clip stencil value is <= 127. - if (sv >= strokeStencilValue) - qWarning("Shape/NVPR: stencil clip ref value %d too large; expect rendering errors", sv); - } - - renderStroke(&d, strokeStencilValue, writeMask); - } - - if (stencilClip) - nvpr.pathStencilFunc(GL_ALWAYS, 0, ~0); - - d.dirty = 0; - } - - f->glBindProgramPipeline(0); -} - -QSGRenderNode::StateFlags QQuickShapeNvprRenderNode::changedStates() const -{ - return BlendState | StencilState | DepthState | ScissorState; -} - -QSGRenderNode::RenderingFlags QQuickShapeNvprRenderNode::flags() const -{ - return DepthAwareRendering; // avoid hitting the less optimal no-opaque-batch path in the renderer -} - -bool QQuickShapeNvprRenderNode::isSupported() -{ - static const bool nvprDisabled = qEnvironmentVariableIntValue("QT_NO_NVPR") != 0; - return !nvprDisabled && QQuickNvprFunctions::isSupported(); -} - -bool QQuickNvprBlitter::create() -{ - if (isCreated()) - destroy(); - - m_program = new QOpenGLShaderProgram; - if (QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile) { - m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/shapes/shaders/blit_core.vert")); - m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/shapes/shaders/blit_core.frag")); - } else { - m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/shapes/shaders/blit.vert")); - m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/shapes/shaders/blit.frag")); - } - m_program->bindAttributeLocation("qt_Vertex", 0); - m_program->bindAttributeLocation("qt_MultiTexCoord0", 1); - if (!m_program->link()) - return false; - - m_matrixLoc = m_program->uniformLocation("qt_Matrix"); - m_opacityLoc = m_program->uniformLocation("qt_Opacity"); - - m_buffer = new QOpenGLBuffer; - if (!m_buffer->create()) - return false; - m_buffer->bind(); - m_buffer->allocate(4 * sizeof(GLfloat) * 6); - m_buffer->release(); - - return true; -} - -void QQuickNvprBlitter::destroy() -{ - if (m_program) { - delete m_program; - m_program = nullptr; - } - if (m_buffer) { - delete m_buffer; - m_buffer = nullptr; - } -} - -void QQuickNvprBlitter::texturedQuad(GLuint textureId, const QSize &size, - const QMatrix4x4 &proj, const QMatrix4x4 &modelview, - float opacity) -{ - QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); - - m_program->bind(); - - QMatrix4x4 m = proj * modelview; - m_program->setUniformValue(m_matrixLoc, m); - m_program->setUniformValue(m_opacityLoc, opacity); - - m_buffer->bind(); - - if (size != m_prevSize) { - m_prevSize = size; - - QPointF p0(size.width() - 1, size.height() - 1); - QPointF p1(0, 0); - QPointF p2(0, size.height() - 1); - QPointF p3(size.width() - 1, 0); - - GLfloat vertices[6 * 4] = { - GLfloat(p0.x()), GLfloat(p0.y()), 1, 0, - GLfloat(p1.x()), GLfloat(p1.y()), 0, 1, - GLfloat(p2.x()), GLfloat(p2.y()), 0, 0, - - GLfloat(p0.x()), GLfloat(p0.y()), 1, 0, - GLfloat(p3.x()), GLfloat(p3.y()), 1, 1, - GLfloat(p1.x()), GLfloat(p1.y()), 0, 1, - }; - - m_buffer->write(0, vertices, sizeof(vertices)); - } - - m_program->enableAttributeArray(0); - m_program->enableAttributeArray(1); - f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr); - f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (const void *) (2 * sizeof(GLfloat))); - - f->glBindTexture(GL_TEXTURE_2D, textureId); - - f->glDrawArrays(GL_TRIANGLES, 0, 6); - - f->glBindTexture(GL_TEXTURE_2D, 0); - m_buffer->release(); - m_program->release(); -} - -QT_END_NAMESPACE diff --git a/src/imports/shapes/qquickshapenvprrenderer_p.h b/src/imports/shapes/qquickshapenvprrenderer_p.h deleted file mode 100644 index f6c9fc169e..0000000000 --- a/src/imports/shapes/qquickshapenvprrenderer_p.h +++ /dev/null @@ -1,237 +0,0 @@ -/**************************************************************************** -** -** 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 QQUICKSHAPENVPRRENDERER_P_H -#define QQUICKSHAPENVPRRENDERER_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 "qquickshape_p_p.h" -#include "qquicknvprfunctions_p.h" -#include -#include -#include -#include - -#if QT_CONFIG(opengl) - -QT_BEGIN_NAMESPACE - -class QQuickShapeNvprRenderNode; -class QOpenGLFramebufferObject; -class QOpenGLBuffer; -class QOpenGLExtraFunctions; - -class QQuickShapeNvprRenderer : public QQuickAbstractPathRenderer -{ -public: - enum Dirty { - DirtyPath = 0x01, - DirtyStyle = 0x02, - DirtyFillRule = 0x04, - DirtyDash = 0x08, - DirtyFillGradient = 0x10, - DirtyList = 0x20 - }; - - void beginSync(int totalCount) override; - void setPath(int index, const QQuickPath *path) override; - void setStrokeColor(int index, const QColor &color) override; - void setStrokeWidth(int index, qreal w) override; - void setFillColor(int index, const QColor &color) override; - void setFillRule(int index, QQuickShapePath::FillRule fillRule) override; - void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override; - void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override; - void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, - qreal dashOffset, const QVector &dashPattern) override; - void setFillGradient(int index, QQuickShapeGradient *gradient) override; - void endSync(bool async) override; - - void updateNode() override; - - void setNode(QQuickShapeNvprRenderNode *node); - - struct NvprPath { - QVector cmd; - QVector coord; - QByteArray str; - }; - -private: - struct ShapePathGuiData { - int dirty = 0; - NvprPath path; - qreal strokeWidth; - QColor strokeColor; - QColor fillColor; - QQuickShapePath::JoinStyle joinStyle; - int miterLimit; - QQuickShapePath::CapStyle capStyle; - QQuickShapePath::FillRule fillRule; - bool dashActive; - qreal dashOffset; - QVector dashPattern; - FillGradientType fillGradientActive; - GradientDesc fillGradient; - }; - - void convertPath(const QQuickPath *path, ShapePathGuiData *d); - - QQuickShapeNvprRenderNode *m_node = nullptr; - int m_accDirty = 0; - - QVector m_sp; -}; - -QDebug operator<<(QDebug debug, const QQuickShapeNvprRenderer::NvprPath &path); - -class QQuickNvprMaterialManager -{ -public: - enum Material { - MatSolid, - MatLinearGradient, - MatRadialGradient, - MatConicalGradient, - - NMaterials - }; - - struct MaterialDesc { - GLuint ppl = 0; - GLuint prg = 0; - int uniLoc[8]; - }; - - void create(QQuickNvprFunctions *nvpr); - MaterialDesc *activateMaterial(Material m); - void releaseResources(); - -private: - QQuickNvprFunctions *m_nvpr = nullptr; - MaterialDesc m_materials[NMaterials]; -}; - -class QQuickNvprBlitter -{ -public: - bool create(); - void destroy(); - bool isCreated() const { return m_program != nullptr; } - void texturedQuad(GLuint textureId, const QSize &size, - const QMatrix4x4 &proj, const QMatrix4x4 &modelview, - float opacity); - -private: - QOpenGLShaderProgram *m_program = nullptr; - QOpenGLBuffer *m_buffer = nullptr; - int m_matrixLoc = -1; - int m_opacityLoc = -1; - QSize m_prevSize; -}; - -class QQuickShapeNvprRenderNode : public QSGRenderNode -{ -public: - ~QQuickShapeNvprRenderNode(); - - void render(const RenderState *state) override; - void releaseResources() override; - StateFlags changedStates() const override; - RenderingFlags flags() const override; - - static bool isSupported(); - -private: - struct ShapePathRenderData { - GLuint path = 0; - int dirty = 0; - QQuickShapeNvprRenderer::NvprPath source; - GLfloat strokeWidth; - QVector4D strokeColor; - QVector4D fillColor; - GLenum joinStyle; - GLint miterLimit; - GLenum capStyle; - GLenum fillRule; - GLfloat dashOffset; - QVector dashPattern; - QQuickAbstractPathRenderer::FillGradientType fillGradientActive; - QQuickAbstractPathRenderer::GradientDesc fillGradient; - QOpenGLFramebufferObject *fallbackFbo = nullptr; - bool fallbackValid = false; - QSize fallbackSize; - QPointF fallbackTopLeft; - - bool hasFill() const { return !qFuzzyIsNull(fillColor.w()) || fillGradientActive; } - bool hasStroke() const { return strokeWidth >= 0.0f && !qFuzzyIsNull(strokeColor.w()); } - }; - - void updatePath(ShapePathRenderData *d); - void renderStroke(ShapePathRenderData *d, int strokeStencilValue, int writeMask); - void renderFill(ShapePathRenderData *d); - void renderOffscreenFill(ShapePathRenderData *d); - void setupStencilForCover(bool stencilClip, int sv); - - static bool nvprInited; - static QQuickNvprFunctions nvpr; - static QQuickNvprMaterialManager mtlmgr; - - QQuickNvprBlitter m_fallbackBlitter; - QOpenGLExtraFunctions *f = nullptr; - - QVector m_sp; - - friend class QQuickShapeNvprRenderer; -}; - -QT_END_NAMESPACE - -#endif // QT_CONFIG(opengl) - -#endif // QQUICKSHAPENVPRRENDERER_P_H diff --git a/src/imports/shapes/qquickshapesoftwarerenderer.cpp b/src/imports/shapes/qquickshapesoftwarerenderer.cpp deleted file mode 100644 index 0f5c3604b5..0000000000 --- a/src/imports/shapes/qquickshapesoftwarerenderer.cpp +++ /dev/null @@ -1,282 +0,0 @@ -/**************************************************************************** -** -** 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 "qquickshapesoftwarerenderer_p.h" -#include - -QT_BEGIN_NAMESPACE - -void QQuickShapeSoftwareRenderer::beginSync(int totalCount) -{ - if (m_sp.count() != totalCount) { - m_sp.resize(totalCount); - m_accDirty |= DirtyList; - } -} - -void QQuickShapeSoftwareRenderer::setPath(int index, const QQuickPath *path) -{ - ShapePathGuiData &d(m_sp[index]); - d.path = path ? path->path() : QPainterPath(); - d.dirty |= DirtyPath; - m_accDirty |= DirtyPath; -} - -void QQuickShapeSoftwareRenderer::setStrokeColor(int index, const QColor &color) -{ - ShapePathGuiData &d(m_sp[index]); - d.pen.setColor(color); - d.dirty |= DirtyPen; - m_accDirty |= DirtyPen; -} - -void QQuickShapeSoftwareRenderer::setStrokeWidth(int index, qreal w) -{ - ShapePathGuiData &d(m_sp[index]); - d.strokeWidth = w; - if (w >= 0.0f) - d.pen.setWidthF(w); - d.dirty |= DirtyPen; - m_accDirty |= DirtyPen; -} - -void QQuickShapeSoftwareRenderer::setFillColor(int index, const QColor &color) -{ - ShapePathGuiData &d(m_sp[index]); - d.fillColor = color; - d.brush.setColor(color); - d.dirty |= DirtyBrush; - m_accDirty |= DirtyBrush; -} - -void QQuickShapeSoftwareRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule) -{ - ShapePathGuiData &d(m_sp[index]); - d.fillRule = Qt::FillRule(fillRule); - d.dirty |= DirtyFillRule; - m_accDirty |= DirtyFillRule; -} - -void QQuickShapeSoftwareRenderer::setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) -{ - ShapePathGuiData &d(m_sp[index]); - d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle)); - d.pen.setMiterLimit(miterLimit); - d.dirty |= DirtyPen; - m_accDirty |= DirtyPen; -} - -void QQuickShapeSoftwareRenderer::setCapStyle(int index, QQuickShapePath::CapStyle capStyle) -{ - ShapePathGuiData &d(m_sp[index]); - d.pen.setCapStyle(Qt::PenCapStyle(capStyle)); - d.dirty |= DirtyPen; - m_accDirty |= DirtyPen; -} - -void QQuickShapeSoftwareRenderer::setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, - qreal dashOffset, const QVector &dashPattern) -{ - ShapePathGuiData &d(m_sp[index]); - switch (strokeStyle) { - case QQuickShapePath::SolidLine: - d.pen.setStyle(Qt::SolidLine); - break; - case QQuickShapePath::DashLine: - d.pen.setStyle(Qt::CustomDashLine); - d.pen.setDashPattern(dashPattern); - d.pen.setDashOffset(dashOffset); - break; - default: - break; - } - d.dirty |= DirtyPen; - m_accDirty |= DirtyPen; -} - -static inline void setupPainterGradient(QGradient *painterGradient, const QQuickShapeGradient &g) -{ - painterGradient->setStops(g.gradientStops()); // sorted - switch (g.spread()) { - case QQuickShapeGradient::PadSpread: - painterGradient->setSpread(QGradient::PadSpread); - break; - case QQuickShapeGradient::RepeatSpread: - painterGradient->setSpread(QGradient::RepeatSpread); - break; - case QQuickShapeGradient::ReflectSpread: - painterGradient->setSpread(QGradient::ReflectSpread); - break; - default: - break; - } -} - -void QQuickShapeSoftwareRenderer::setFillGradient(int index, QQuickShapeGradient *gradient) -{ - ShapePathGuiData &d(m_sp[index]); - if (QQuickShapeLinearGradient *g = qobject_cast(gradient)) { - QLinearGradient painterGradient(g->x1(), g->y1(), g->x2(), g->y2()); - setupPainterGradient(&painterGradient, *g); - d.brush = QBrush(painterGradient); - } else if (QQuickShapeRadialGradient *g = qobject_cast(gradient)) { - QRadialGradient painterGradient(g->centerX(), g->centerY(), g->centerRadius(), - g->focalX(), g->focalY(), g->focalRadius()); - setupPainterGradient(&painterGradient, *g); - d.brush = QBrush(painterGradient); - } else if (QQuickShapeConicalGradient *g = qobject_cast(gradient)) { - QConicalGradient painterGradient(g->centerX(), g->centerY(), g->angle()); - setupPainterGradient(&painterGradient, *g); - d.brush = QBrush(painterGradient); - } else { - d.brush = QBrush(d.fillColor); - } - d.dirty |= DirtyBrush; - m_accDirty |= DirtyBrush; -} - -void QQuickShapeSoftwareRenderer::endSync(bool) -{ -} - -void QQuickShapeSoftwareRenderer::setNode(QQuickShapeSoftwareRenderNode *node) -{ - if (m_node != node) { - m_node = node; - m_accDirty |= DirtyList; - } -} - -void QQuickShapeSoftwareRenderer::updateNode() -{ - if (!m_accDirty) - return; - - const int count = m_sp.count(); - const bool listChanged = m_accDirty & DirtyList; - if (listChanged) - m_node->m_sp.resize(count); - - m_node->m_boundingRect = QRectF(); - - for (int i = 0; i < count; ++i) { - ShapePathGuiData &src(m_sp[i]); - QQuickShapeSoftwareRenderNode::ShapePathRenderData &dst(m_node->m_sp[i]); - - if (listChanged || (src.dirty & DirtyPath)) { - dst.path = src.path; - dst.path.setFillRule(src.fillRule); - } - - if (listChanged || (src.dirty & DirtyFillRule)) - dst.path.setFillRule(src.fillRule); - - if (listChanged || (src.dirty & DirtyPen)) { - dst.pen = src.pen; - dst.strokeWidth = src.strokeWidth; - } - - if (listChanged || (src.dirty & DirtyBrush)) - dst.brush = src.brush; - - src.dirty = 0; - - QRectF br = dst.path.boundingRect(); - const float sw = qMax(1.0f, dst.strokeWidth); - br.adjust(-sw, -sw, sw, sw); - m_node->m_boundingRect |= br; - } - - m_node->markDirty(QSGNode::DirtyMaterial); - m_accDirty = 0; -} - -QQuickShapeSoftwareRenderNode::QQuickShapeSoftwareRenderNode(QQuickShape *item) - : m_item(item) -{ -} - -QQuickShapeSoftwareRenderNode::~QQuickShapeSoftwareRenderNode() -{ - releaseResources(); -} - -void QQuickShapeSoftwareRenderNode::releaseResources() -{ -} - -void QQuickShapeSoftwareRenderNode::render(const RenderState *state) -{ - if (m_sp.isEmpty()) - return; - - QSGRendererInterface *rif = m_item->window()->rendererInterface(); - QPainter *p = static_cast(rif->getResource(m_item->window(), QSGRendererInterface::PainterResource)); - Q_ASSERT(p); - - const QRegion *clipRegion = state->clipRegion(); - if (clipRegion && !clipRegion->isEmpty()) - p->setClipRegion(*clipRegion, Qt::ReplaceClip); // must be done before setTransform - - p->setTransform(matrix()->toTransform()); - p->setOpacity(inheritedOpacity()); - - for (const ShapePathRenderData &d : qAsConst(m_sp)) { - p->setPen(d.strokeWidth >= 0.0f && d.pen.color() != Qt::transparent ? d.pen : Qt::NoPen); - p->setBrush(d.brush.color() != Qt::transparent ? d.brush : Qt::NoBrush); - p->drawPath(d.path); - } -} - -QSGRenderNode::StateFlags QQuickShapeSoftwareRenderNode::changedStates() const -{ - return nullptr; -} - -QSGRenderNode::RenderingFlags QQuickShapeSoftwareRenderNode::flags() const -{ - return BoundedRectRendering; // avoid fullscreen updates by saying we won't draw outside rect() -} - -QRectF QQuickShapeSoftwareRenderNode::rect() const -{ - return m_boundingRect; -} - -QT_END_NAMESPACE diff --git a/src/imports/shapes/qquickshapesoftwarerenderer_p.h b/src/imports/shapes/qquickshapesoftwarerenderer_p.h deleted file mode 100644 index 0abc2e37b0..0000000000 --- a/src/imports/shapes/qquickshapesoftwarerenderer_p.h +++ /dev/null @@ -1,135 +0,0 @@ -/**************************************************************************** -** -** 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 QQUICKSHAPESOFTWARERENDERER_P_H -#define QQUICKSHAPESOFTWARERENDERER_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 "qquickshape_p_p.h" -#include -#include -#include - -QT_BEGIN_NAMESPACE - -class QQuickShapeSoftwareRenderNode; - -class QQuickShapeSoftwareRenderer : public QQuickAbstractPathRenderer -{ -public: - enum Dirty { - DirtyPath = 0x01, - DirtyPen = 0x02, - DirtyFillRule = 0x04, - DirtyBrush = 0x08, - DirtyList = 0x10 - }; - - void beginSync(int totalCount) override; - void setPath(int index, const QQuickPath *path) override; - void setStrokeColor(int index, const QColor &color) override; - void setStrokeWidth(int index, qreal w) override; - void setFillColor(int index, const QColor &color) override; - void setFillRule(int index, QQuickShapePath::FillRule fillRule) override; - void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override; - void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override; - void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, - qreal dashOffset, const QVector &dashPattern) override; - void setFillGradient(int index, QQuickShapeGradient *gradient) override; - void endSync(bool async) override; - - void updateNode() override; - - void setNode(QQuickShapeSoftwareRenderNode *node); - -private: - QQuickShapeSoftwareRenderNode *m_node = nullptr; - int m_accDirty = 0; - struct ShapePathGuiData { - int dirty = 0; - QPainterPath path; - QPen pen; - float strokeWidth; - QColor fillColor; - QBrush brush; - Qt::FillRule fillRule; - }; - QVector m_sp; -}; - -class QQuickShapeSoftwareRenderNode : public QSGRenderNode -{ -public: - QQuickShapeSoftwareRenderNode(QQuickShape *item); - ~QQuickShapeSoftwareRenderNode(); - - void render(const RenderState *state) override; - void releaseResources() override; - StateFlags changedStates() const override; - RenderingFlags flags() const override; - QRectF rect() const override; - -private: - QQuickShape *m_item; - - struct ShapePathRenderData { - QPainterPath path; - QPen pen; - float strokeWidth; - QBrush brush; - }; - QVector m_sp; - QRectF m_boundingRect; - - friend class QQuickShapeSoftwareRenderer; -}; - -QT_END_NAMESPACE - -#endif // QQUICKSHAPESOFTWARERENDERER_P_H diff --git a/src/imports/shapes/qtquickshapesplugin.qrc b/src/imports/shapes/qtquickshapesplugin.qrc deleted file mode 100644 index f139861693..0000000000 --- a/src/imports/shapes/qtquickshapesplugin.qrc +++ /dev/null @@ -1,20 +0,0 @@ - - - shaders/blit.vert - shaders/blit.frag - shaders/blit_core.frag - shaders/blit_core.vert - shaders/lineargradient.vert - shaders/lineargradient.frag - shaders/lineargradient_core.vert - shaders/lineargradient_core.frag - shaders/radialgradient.vert - shaders/radialgradient.frag - shaders/radialgradient_core.vert - shaders/radialgradient_core.frag - shaders/conicalgradient.vert - shaders/conicalgradient.frag - shaders/conicalgradient_core.vert - shaders/conicalgradient_core.frag - - diff --git a/src/imports/shapes/shaders/blit.frag b/src/imports/shapes/shaders/blit.frag deleted file mode 100644 index 505f0db179..0000000000 --- a/src/imports/shapes/shaders/blit.frag +++ /dev/null @@ -1,9 +0,0 @@ -varying highp vec2 qt_TexCoord0; - -uniform sampler2D source; -uniform lowp float qt_Opacity; - -void main() -{ - gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity; -} diff --git a/src/imports/shapes/shaders/blit.vert b/src/imports/shapes/shaders/blit.vert deleted file mode 100644 index f8306bd945..0000000000 --- a/src/imports/shapes/shaders/blit.vert +++ /dev/null @@ -1,12 +0,0 @@ -uniform highp mat4 qt_Matrix; - -attribute highp vec4 qt_Vertex; -attribute highp vec2 qt_MultiTexCoord0; - -varying highp vec2 qt_TexCoord0; - -void main() -{ - qt_TexCoord0 = qt_MultiTexCoord0; - gl_Position = qt_Matrix * qt_Vertex; -} diff --git a/src/imports/shapes/shaders/blit_core.frag b/src/imports/shapes/shaders/blit_core.frag deleted file mode 100644 index 7073808fba..0000000000 --- a/src/imports/shapes/shaders/blit_core.frag +++ /dev/null @@ -1,13 +0,0 @@ -#version 150 core - -in vec2 qt_TexCoord0; - -out vec4 fragColor; - -uniform sampler2D source; -uniform float qt_Opacity; - -void main() -{ - fragColor = texture(source, qt_TexCoord0) * qt_Opacity; -} diff --git a/src/imports/shapes/shaders/blit_core.vert b/src/imports/shapes/shaders/blit_core.vert deleted file mode 100644 index 5246441da3..0000000000 --- a/src/imports/shapes/shaders/blit_core.vert +++ /dev/null @@ -1,14 +0,0 @@ -#version 150 core - -in vec4 qt_Vertex; -in vec2 qt_MultiTexCoord0; - -out vec2 qt_TexCoord0; - -uniform mat4 qt_Matrix; - -void main() -{ - qt_TexCoord0 = qt_MultiTexCoord0; - gl_Position = qt_Matrix * qt_Vertex; -} diff --git a/src/imports/shapes/shaders/conicalgradient.frag b/src/imports/shapes/shaders/conicalgradient.frag deleted file mode 100644 index af5fdd5ee0..0000000000 --- a/src/imports/shapes/shaders/conicalgradient.frag +++ /dev/null @@ -1,19 +0,0 @@ -#define INVERSE_2PI 0.1591549430918953358 - -uniform sampler2D gradTabTexture; -uniform lowp float opacity; - -uniform highp float angle; - -varying highp vec2 coord; - -void main() -{ - highp float t; - if (abs(coord.y) == abs(coord.x)) - t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI; - else - t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI; - gl_FragColor = texture2D(gradTabTexture, vec2(t - floor(t), 0.5)) * opacity; - -} diff --git a/src/imports/shapes/shaders/conicalgradient.vert b/src/imports/shapes/shaders/conicalgradient.vert deleted file mode 100644 index 3350b0675a..0000000000 --- a/src/imports/shapes/shaders/conicalgradient.vert +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec4 vertexCoord; -attribute vec4 vertexColor; - -uniform mat4 matrix; -uniform vec2 translationPoint; - -varying vec2 coord; - -void main() -{ - coord = vertexCoord.xy - translationPoint; - gl_Position = matrix * vertexCoord; -} diff --git a/src/imports/shapes/shaders/conicalgradient_core.frag b/src/imports/shapes/shaders/conicalgradient_core.frag deleted file mode 100644 index e18b80159a..0000000000 --- a/src/imports/shapes/shaders/conicalgradient_core.frag +++ /dev/null @@ -1,22 +0,0 @@ -#version 150 core - -#define INVERSE_2PI 0.1591549430918953358 - -uniform sampler2D gradTabTexture; -uniform float opacity; - -uniform float angle; - -in vec2 coord; - -out vec4 fragColor; - -void main() -{ - float t; - if (abs(coord.y) == abs(coord.x)) - t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI; - else - t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI; - fragColor = texture(gradTabTexture, vec2(t - floor(t), 0.5)) * opacity; -} diff --git a/src/imports/shapes/shaders/conicalgradient_core.vert b/src/imports/shapes/shaders/conicalgradient_core.vert deleted file mode 100644 index f94a56401b..0000000000 --- a/src/imports/shapes/shaders/conicalgradient_core.vert +++ /dev/null @@ -1,15 +0,0 @@ -#version 150 core - -in vec4 vertexCoord; -in vec4 vertexColor; - -uniform mat4 matrix; -uniform vec2 translationPoint; - -out vec2 coord; - -void main() -{ - coord = vertexCoord.xy - translationPoint; - gl_Position = matrix * vertexCoord; -} diff --git a/src/imports/shapes/shaders/lineargradient.frag b/src/imports/shapes/shaders/lineargradient.frag deleted file mode 100644 index 7f4a739109..0000000000 --- a/src/imports/shapes/shaders/lineargradient.frag +++ /dev/null @@ -1,9 +0,0 @@ -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/imports/shapes/shaders/lineargradient.vert b/src/imports/shapes/shaders/lineargradient.vert deleted file mode 100644 index eb21b8886b..0000000000 --- a/src/imports/shapes/shaders/lineargradient.vert +++ /dev/null @@ -1,15 +0,0 @@ -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/imports/shapes/shaders/lineargradient_core.frag b/src/imports/shapes/shaders/lineargradient_core.frag deleted file mode 100644 index 5908acfa67..0000000000 --- a/src/imports/shapes/shaders/lineargradient_core.frag +++ /dev/null @@ -1,12 +0,0 @@ -#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/imports/shapes/shaders/lineargradient_core.vert b/src/imports/shapes/shaders/lineargradient_core.vert deleted file mode 100644 index 60b56f38e3..0000000000 --- a/src/imports/shapes/shaders/lineargradient_core.vert +++ /dev/null @@ -1,17 +0,0 @@ -#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/imports/shapes/shaders/radialgradient.frag b/src/imports/shapes/shaders/radialgradient.frag deleted file mode 100644 index 0f503bc0f7..0000000000 --- a/src/imports/shapes/shaders/radialgradient.frag +++ /dev/null @@ -1,25 +0,0 @@ -uniform sampler2D gradTabTexture; -uniform lowp float opacity; - -uniform highp vec2 focalToCenter; -uniform highp float centerRadius; -uniform highp float focalRadius; - -varying highp vec2 coord; - -void main() -{ - highp float rd = centerRadius - focalRadius; - highp float b = 2.0 * (rd * focalRadius + dot(coord, focalToCenter)); - highp float fmp2_m_radius2 = -focalToCenter.x * focalToCenter.x - focalToCenter.y * focalToCenter.y + rd * rd; - highp float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2); - highp float det = b * b - 4.0 * fmp2_m_radius2 * ((focalRadius * focalRadius) - dot(coord, coord)); - lowp vec4 result = vec4(0.0); - if (det >= 0.0) { - highp float detSqrt = sqrt(det); - highp float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); - if (focalRadius + w * (centerRadius - focalRadius) >= 0.0) - result = texture2D(gradTabTexture, vec2(w, 0.5)) * opacity; - } - gl_FragColor = result; -} diff --git a/src/imports/shapes/shaders/radialgradient.vert b/src/imports/shapes/shaders/radialgradient.vert deleted file mode 100644 index 3350b0675a..0000000000 --- a/src/imports/shapes/shaders/radialgradient.vert +++ /dev/null @@ -1,13 +0,0 @@ -attribute vec4 vertexCoord; -attribute vec4 vertexColor; - -uniform mat4 matrix; -uniform vec2 translationPoint; - -varying vec2 coord; - -void main() -{ - coord = vertexCoord.xy - translationPoint; - gl_Position = matrix * vertexCoord; -} diff --git a/src/imports/shapes/shaders/radialgradient_core.frag b/src/imports/shapes/shaders/radialgradient_core.frag deleted file mode 100644 index 706ce53e4d..0000000000 --- a/src/imports/shapes/shaders/radialgradient_core.frag +++ /dev/null @@ -1,29 +0,0 @@ -#version 150 core - -uniform sampler2D gradTabTexture; -uniform float opacity; - -uniform vec2 focalToCenter; -uniform float centerRadius; -uniform float focalRadius; - -in vec2 coord; - -out vec4 fragColor; - -void main() -{ - float rd = centerRadius - focalRadius; - float b = 2.0 * (rd * focalRadius + dot(coord, focalToCenter)); - float fmp2_m_radius2 = -focalToCenter.x * focalToCenter.x - focalToCenter.y * focalToCenter.y + rd * rd; - float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2); - float det = b * b - 4.0 * fmp2_m_radius2 * ((focalRadius * focalRadius) - dot(coord, coord)); - vec4 result = vec4(0.0); - if (det >= 0.0) { - float detSqrt = sqrt(det); - float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); - if (focalRadius + w * (centerRadius - focalRadius) >= 0.0) - result = texture(gradTabTexture, vec2(w, 0.5)) * opacity; - } - fragColor = result; -} diff --git a/src/imports/shapes/shaders/radialgradient_core.vert b/src/imports/shapes/shaders/radialgradient_core.vert deleted file mode 100644 index f94a56401b..0000000000 --- a/src/imports/shapes/shaders/radialgradient_core.vert +++ /dev/null @@ -1,15 +0,0 @@ -#version 150 core - -in vec4 vertexCoord; -in vec4 vertexColor; - -uniform mat4 matrix; -uniform vec2 translationPoint; - -out vec2 coord; - -void main() -{ - coord = vertexCoord.xy - translationPoint; - gl_Position = matrix * vertexCoord; -} diff --git a/src/imports/shapes/shapes.pro b/src/imports/shapes/shapes.pro index 4d6e9508af..71bb456866 100644 --- a/src/imports/shapes/shapes.pro +++ b/src/imports/shapes/shapes.pro @@ -3,31 +3,9 @@ TARGET = qmlshapesplugin TARGETPATH = QtQuick/Shapes IMPORT_VERSION = 1.11 -QT = core gui-private qml quick-private - -HEADERS += \ - qquickshape_p.h \ - qquickshape_p_p.h \ - qquickshapegenericrenderer_p.h \ - qquickshapesoftwarerenderer_p.h +QT = core gui-private qml quick-private quickshapes-private SOURCES += \ plugin.cpp \ - qquickshape.cpp \ - qquickshapegenericrenderer.cpp \ - qquickshapesoftwarerenderer.cpp - -qtConfig(opengl) { - HEADERS += \ - qquicknvprfunctions_p.h \ - qquicknvprfunctions_p_p.h \ - qquickshapenvprrenderer_p.h - - SOURCES += \ - qquicknvprfunctions.cpp \ - qquickshapenvprrenderer.cpp -} - -RESOURCES += qtquickshapesplugin.qrc load(qml_plugin) diff --git a/src/quickshapes/qquicknvprfunctions.cpp b/src/quickshapes/qquicknvprfunctions.cpp new file mode 100644 index 0000000000..409a59be7f --- /dev/null +++ b/src/quickshapes/qquicknvprfunctions.cpp @@ -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$ +** +****************************************************************************/ + +#include "qquicknvprfunctions_p.h" + +#if QT_CONFIG(opengl) + +#include +#include +#include +#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; +} + +#define PROC(type, name) reinterpret_cast(ctx->getProcAddress(#name)) + +/*! + \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 tempContext; + QScopedPointer 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; + + // Check that GL_NV_Path_rendering extension is at least API revision 1.3 + if (!PROC(PFNGLPROGRAMPATHFRAGMENTINPUTGENNVPROC, glProgramPathFragmentInputGenNV)) + 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; +} + +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->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->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_CONFIG(opengl) diff --git a/src/quickshapes/qquicknvprfunctions_p.h b/src/quickshapes/qquicknvprfunctions_p.h new file mode 100644 index 0000000000..92246cf4c8 --- /dev/null +++ b/src/quickshapes/qquicknvprfunctions_p.h @@ -0,0 +1,401 @@ +/**************************************************************************** +** +** 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 +#include +#include + +#if QT_CONFIG(opengl) + +QT_BEGIN_NAMESPACE + +// note: fixed pipeline specific functions are removed - modern ES ext +// headers have all this, but not the fixed stuff + +#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 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 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 + +// this one originates from fixed pipeline so may not be in GLES ext headers, but we need it still +#ifndef GL_OBJECT_LINEAR_NV +#define GL_OBJECT_LINEAR_NV 0x2401 +#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; + 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; + 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_CONFIG(opengl) + +#endif // QQUICKNVPRFUNCTIONS_P_H diff --git a/src/quickshapes/qquicknvprfunctions_p_p.h b/src/quickshapes/qquicknvprfunctions_p_p.h new file mode 100644 index 0000000000..3d9ca0de9f --- /dev/null +++ b/src/quickshapes/qquicknvprfunctions_p_p.h @@ -0,0 +1,71 @@ +/**************************************************************************** +** +** 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 +#include + +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/quickshapes/qquickshape.cpp b/src/quickshapes/qquickshape.cpp new file mode 100644 index 0000000000..edfa308c4d --- /dev/null +++ b/src/quickshapes/qquickshape.cpp @@ -0,0 +1,1620 @@ +/**************************************************************************** +** +** 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 "qquickshape_p.h" +#include "qquickshape_p_p.h" +#include "qquickshapegenericrenderer_p.h" +#include "qquickshapenvprrenderer_p.h" +#include "qquickshapesoftwarerenderer_p.h" +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(QQSHAPE_LOG_TIME_DIRTY_SYNC, "qt.shape.time.sync") + +/*! + \qmlmodule QtQuick.Shapes 1.11 + \title Qt Quick Shapes QML Types + \ingroup qmlmodules + \brief Provides QML types for drawing stroked and filled shapes. + + To use the types in this module, import the module with the following line: + + \badcode + import QtQuick.Shapes 1.11 + \endcode +*/ + +QQuickShapeStrokeFillParams::QQuickShapeStrokeFillParams() + : strokeColor(Qt::white), + strokeWidth(1), + fillColor(Qt::white), + fillRule(QQuickShapePath::OddEvenFill), + joinStyle(QQuickShapePath::BevelJoin), + miterLimit(2), + capStyle(QQuickShapePath::SquareCap), + strokeStyle(QQuickShapePath::SolidLine), + dashOffset(0), + fillGradient(nullptr) +{ + dashPattern << 4 << 2; // 4 * strokeWidth dash followed by 2 * strokeWidth space +} + +/*! + \qmltype ShapePath + \instantiates QQuickShapePath + \inqmlmodule QtQuick.Shapes + \ingroup qtquick-paths + \ingroup qtquick-views + \inherits Path + \brief Describes a Path and associated properties for stroking and filling. + \since 5.10 + + A \l Shape contains one or more ShapePath elements. At least one ShapePath is + necessary in order to have a Shape output anything visible. A ShapePath + itself is a \l Path with additional properties describing the stroking and + filling parameters, such as the stroke width and color, the fill color or + gradient, join and cap styles, and so on. As with ordinary \l Path objects, + ShapePath also contains a list of path elements like \l PathMove, \l PathLine, + \l PathCubic, \l PathQuad, \l PathArc, together with a starting position. + + Any property changes in these data sets will be bubble up and change the + output of the Shape. This means that it is simple and easy to change, or + even animate, the starting and ending position, control points, or any + stroke or fill parameters using the usual QML bindings and animation types + like NumberAnimation. + + In the following example the line join style changes automatically based on + the value of joinStyleIndex: + + \qml + ShapePath { + strokeColor: "black" + strokeWidth: 16 + fillColor: "transparent" + capStyle: ShapePath.RoundCap + + property int joinStyleIndex: 0 + + property variant styles: [ + ShapePath.BevelJoin, + ShapePath.MiterJoin, + ShapePath.RoundJoin + ] + + joinStyle: styles[joinStyleIndex] + + startX: 30 + startY: 30 + PathLine { x: 100; y: 100 } + PathLine { x: 30; y: 100 } + } + \endqml + + Once associated with a Shape, here is the output with a joinStyleIndex + of 2 (ShapePath.RoundJoin): + + \image visualpath-code-example.png + + \sa {Qt Quick Examples - Shapes}, Shape + */ + +QQuickShapePathPrivate::QQuickShapePathPrivate() + : dirty(DirtyAll) +{ + // Set this QQuickPath to be a ShapePath + isShapePath = true; +} + +QQuickShapePath::QQuickShapePath(QObject *parent) + : QQuickPath(*(new QQuickShapePathPrivate), parent) +{ + // The inherited changed() and the shapePathChanged() signals remain + // distinct, and this is intentional. Combining the two is not possible due + // to the difference in semantics and the need to act (see dirty flag + // below) differently on QQuickPath-related changes. + + connect(this, &QQuickPath::changed, [this]() { + Q_D(QQuickShapePath); + d->dirty |= QQuickShapePathPrivate::DirtyPath; + emit shapePathChanged(); + }); +} + +QQuickShapePath::~QQuickShapePath() +{ +} + +/*! + \qmlproperty color QtQuick.Shapes::ShapePath::strokeColor + + This property holds the stroking color. + + When set to \c transparent, no stroking occurs. + + The default value is \c white. + */ + +QColor QQuickShapePath::strokeColor() const +{ + Q_D(const QQuickShapePath); + return d->sfp.strokeColor; +} + +void QQuickShapePath::setStrokeColor(const QColor &color) +{ + Q_D(QQuickShapePath); + if (d->sfp.strokeColor != color) { + d->sfp.strokeColor = color; + d->dirty |= QQuickShapePathPrivate::DirtyStrokeColor; + emit strokeColorChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty color QtQuick.Shapes::ShapePath::strokeWidth + + This property holds the stroke width. + + When set to a negative value, no stroking occurs. + + The default value is 1. + */ + +qreal QQuickShapePath::strokeWidth() const +{ + Q_D(const QQuickShapePath); + return d->sfp.strokeWidth; +} + +void QQuickShapePath::setStrokeWidth(qreal w) +{ + Q_D(QQuickShapePath); + if (d->sfp.strokeWidth != w) { + d->sfp.strokeWidth = w; + d->dirty |= QQuickShapePathPrivate::DirtyStrokeWidth; + emit strokeWidthChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty color QtQuick.Shapes::ShapePath::fillColor + + This property holds the fill color. + + When set to \c transparent, no filling occurs. + + The default value is \c white. + */ + +QColor QQuickShapePath::fillColor() const +{ + Q_D(const QQuickShapePath); + return d->sfp.fillColor; +} + +void QQuickShapePath::setFillColor(const QColor &color) +{ + Q_D(QQuickShapePath); + if (d->sfp.fillColor != color) { + d->sfp.fillColor = color; + d->dirty |= QQuickShapePathPrivate::DirtyFillColor; + emit fillColorChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty enumeration QtQuick.Shapes::ShapePath::fillRule + + This property holds the fill rule. The default value is + \c ShapePath.OddEvenFill. For an explanation on fill rules, see + QPainterPath::setFillRule(). + + \value ShapePath.OddEvenFill + Odd-even fill rule. + + \value ShapePath.WindingFill + Non-zero winding fill rule. + */ + +QQuickShapePath::FillRule QQuickShapePath::fillRule() const +{ + Q_D(const QQuickShapePath); + return d->sfp.fillRule; +} + +void QQuickShapePath::setFillRule(FillRule fillRule) +{ + Q_D(QQuickShapePath); + if (d->sfp.fillRule != fillRule) { + d->sfp.fillRule = fillRule; + d->dirty |= QQuickShapePathPrivate::DirtyFillRule; + emit fillRuleChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty enumeration QtQuick.Shapes::ShapePath::joinStyle + + This property defines how joins between two connected lines are drawn. The + default value is \c ShapePath.BevelJoin. + + \value ShapePath.MiterJoin + The outer edges of the lines are extended to meet at an angle, and + this area is filled. + + \value ShapePath.BevelJoin + The triangular notch between the two lines is filled. + + \value ShapePath.RoundJoin + A circular arc between the two lines is filled. + */ + +QQuickShapePath::JoinStyle QQuickShapePath::joinStyle() const +{ + Q_D(const QQuickShapePath); + return d->sfp.joinStyle; +} + +void QQuickShapePath::setJoinStyle(JoinStyle style) +{ + Q_D(QQuickShapePath); + if (d->sfp.joinStyle != style) { + d->sfp.joinStyle = style; + d->dirty |= QQuickShapePathPrivate::DirtyStyle; + emit joinStyleChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty int QtQuick.Shapes::ShapePath::miterLimit + + When joinStyle is set to \c ShapePath.MiterJoin, this property + specifies how far the miter join can extend from the join point. + + The default value is 2. + */ + +int QQuickShapePath::miterLimit() const +{ + Q_D(const QQuickShapePath); + return d->sfp.miterLimit; +} + +void QQuickShapePath::setMiterLimit(int limit) +{ + Q_D(QQuickShapePath); + if (d->sfp.miterLimit != limit) { + d->sfp.miterLimit = limit; + d->dirty |= QQuickShapePathPrivate::DirtyStyle; + emit miterLimitChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty enumeration QtQuick.Shapes::ShapePath::capStyle + + This property defines how the end points of lines are drawn. The + default value is \c ShapePath.SquareCap. + + \value ShapePath.FlatCap + A square line end that does not cover the end point of the line. + + \value ShapePath.SquareCap + A square line end that covers the end point and extends beyond it + by half the line width. + + \value ShapePath.RoundCap + A rounded line end. + */ + +QQuickShapePath::CapStyle QQuickShapePath::capStyle() const +{ + Q_D(const QQuickShapePath); + return d->sfp.capStyle; +} + +void QQuickShapePath::setCapStyle(CapStyle style) +{ + Q_D(QQuickShapePath); + if (d->sfp.capStyle != style) { + d->sfp.capStyle = style; + d->dirty |= QQuickShapePathPrivate::DirtyStyle; + emit capStyleChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty enumeration QtQuick.Shapes::ShapePath::strokeStyle + + This property defines the style of stroking. The default value is + ShapePath.SolidLine. + + \list + \li ShapePath.SolidLine - A plain line. + \li ShapePath.DashLine - Dashes separated by a few pixels. + \endlist + */ + +QQuickShapePath::StrokeStyle QQuickShapePath::strokeStyle() const +{ + Q_D(const QQuickShapePath); + return d->sfp.strokeStyle; +} + +void QQuickShapePath::setStrokeStyle(StrokeStyle style) +{ + Q_D(QQuickShapePath); + if (d->sfp.strokeStyle != style) { + d->sfp.strokeStyle = style; + d->dirty |= QQuickShapePathPrivate::DirtyDash; + emit strokeStyleChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty real QtQuick.Shapes::ShapePath::dashOffset + + This property defines the starting point on the dash pattern, measured in + units used to specify the dash pattern. + + The default value is 0. + + \sa QPen::setDashOffset() + */ + +qreal QQuickShapePath::dashOffset() const +{ + Q_D(const QQuickShapePath); + return d->sfp.dashOffset; +} + +void QQuickShapePath::setDashOffset(qreal offset) +{ + Q_D(QQuickShapePath); + if (d->sfp.dashOffset != offset) { + d->sfp.dashOffset = offset; + d->dirty |= QQuickShapePathPrivate::DirtyDash; + emit dashOffsetChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty list QtQuick.Shapes::ShapePath::dashPattern + + This property defines the dash pattern when ShapePath.strokeStyle is set + to ShapePath.DashLine. The pattern must be specified as an even number of + positive entries where the entries 1, 3, 5... are the dashes and 2, 4, + 6... are the spaces. The pattern is specified in units of the pen's width. + + The default value is (4, 2), meaning a dash of 4 * ShapePath.strokeWidth + pixels followed by a space of 2 * ShapePath.strokeWidth pixels. + + \sa QPen::setDashPattern() + */ + +QVector QQuickShapePath::dashPattern() const +{ + Q_D(const QQuickShapePath); + return d->sfp.dashPattern; +} + +void QQuickShapePath::setDashPattern(const QVector &array) +{ + Q_D(QQuickShapePath); + if (d->sfp.dashPattern != array) { + d->sfp.dashPattern = array; + d->dirty |= QQuickShapePathPrivate::DirtyDash; + emit dashPatternChanged(); + emit shapePathChanged(); + } +} + +/*! + \qmlproperty ShapeGradient QtQuick.Shapes::ShapePath::fillGradient + + This property defines the fill gradient. By default no gradient is enabled + and the value is \c null. In this case the fill uses a solid color based + on the value of ShapePath.fillColor. + + When set, ShapePath.fillColor is ignored and filling is done using one of + the ShapeGradient subtypes. + + \note The Gradient type cannot be used here. Rather, prefer using one of + the advanced subtypes, like LinearGradient. + */ + +QQuickShapeGradient *QQuickShapePath::fillGradient() const +{ + Q_D(const QQuickShapePath); + return d->sfp.fillGradient; +} + +void QQuickShapePath::setFillGradient(QQuickShapeGradient *gradient) +{ + Q_D(QQuickShapePath); + if (d->sfp.fillGradient != gradient) { + if (d->sfp.fillGradient) + qmlobject_disconnect(d->sfp.fillGradient, QQuickShapeGradient, SIGNAL(updated()), + this, QQuickShapePath, SLOT(_q_fillGradientChanged())); + d->sfp.fillGradient = gradient; + if (d->sfp.fillGradient) + qmlobject_connect(d->sfp.fillGradient, QQuickShapeGradient, SIGNAL(updated()), + this, QQuickShapePath, SLOT(_q_fillGradientChanged())); + d->dirty |= QQuickShapePathPrivate::DirtyFillGradient; + emit shapePathChanged(); + } +} + +void QQuickShapePathPrivate::_q_fillGradientChanged() +{ + Q_Q(QQuickShapePath); + dirty |= DirtyFillGradient; + emit q->shapePathChanged(); +} + +void QQuickShapePath::resetFillGradient() +{ + setFillGradient(nullptr); +} + +/*! + \qmltype Shape + \instantiates QQuickShape + \inqmlmodule QtQuick.Shapes + \ingroup qtquick-paths + \ingroup qtquick-views + \inherits Item + \brief Renders a path. + \since 5.10 + + Renders a path either by generating geometry via QPainterPath and manual + triangulation or by using a GPU vendor 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 Shape is suitable for creating shapes spreading over larger + areas of the screen, avoiding the performance penalty for texture uploads + or framebuffer blits. In addition, the declarative API allows manipulating, + binding to, and even animating the path element properties like starting + and ending position, the control points, and so on. + + The types for specifying path elements are shared between \l PathView and + Shape. However, not all Shape implementations support all path + element types, while some may not make sense for PathView. Shape's + currently supported subset is: PathMove, PathLine, PathQuad, PathCubic, + PathArc, and PathSvg. + + See \l Path for a detailed overview of the supported path elements. + + \qml + Shape { + width: 200 + height: 150 + anchors.centerIn: parent + ShapePath { + strokeWidth: 4 + strokeColor: "red" + fillGradient: LinearGradient { + x1: 20; y1: 20 + x2: 180; y2: 130 + GradientStop { position: 0; color: "blue" } + GradientStop { position: 0.2; color: "green" } + GradientStop { position: 0.4; color: "red" } + GradientStop { position: 0.6; color: "yellow" } + GradientStop { position: 1; color: "cyan" } + } + strokeStyle: ShapePath.DashLine + dashPattern: [ 1, 4 ] + startX: 20; startY: 20 + PathLine { x: 180; y: 130 } + PathLine { x: 20; y: 130 } + PathLine { x: 20; y: 20 } + } + } + \endqml + + \image pathitem-code-example.png + + Like \l Item, Shape also allows any visual or non-visual objects to be + declared as children. ShapePath objects are handled specially. This is + useful since it allows adding visual items, like \l Rectangle or \l Image, + and non-visual objects, like \l Timer directly as children of Shape. + + The following list summarizes the available Shape rendering approaches: + + \list + + \li When running with the default, OpenGL backend of Qt Quick, both the + generic, triangulation-based and the NVIDIA-specific + \c{GL_NV_path_rendering} methods are available. The choice is made at + runtime, depending on the graphics driver's capabilities. When this is not + desired, applications can force using the generic method by setting the + Shape.vendorExtensionsEnabled property to \c false. + + \li The \c software backend is fully supported. The path is rendered via + QPainter::strokePath() and QPainter::fillPath() in this case. + + \li The Direct 3D 12 backend is not currently supported. + + \li The OpenVG backend is not currently supported. + + \endlist + + When using Shape, it is important to be aware of potential performance + implications: + + \list + + \li When the application is running with the generic, triangulation-based + Shape implementation, the geometry generation happens entirely on the + CPU. This is potentially expensive. Changing the set of path elements, + changing the properties of these elements, or changing certain properties + of the Shape itself all lead to retriangulation of the affected paths on + every change. Therefore, applying animation to such properties can affect + performance on less powerful systems. + + \li However, the data-driven, declarative nature of the Shape API often + means better cacheability for the underlying CPU and GPU resources. A + property change in one ShapePath will only lead to reprocessing the + affected ShapePath, leaving other parts of the Shape unchanged. Therefore, + a frequently changing property can still result in a lower overall system + load than with imperative painting approaches (for example, QPainter). + + \li 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 property changes is smaller. + + \li At the same time, attention must be paid to the number of Shape + elements in the scene, in particular when using this special accelerated + approach for \c{GL_NV_path_rendering}. The way such a Shape item is + represented in the scene graph is different from an ordinary + geometry-based item, and incurs a certain cost when it comes to OpenGL + state changes. + + \li As a general rule, scenes should avoid using separate Shape items when + it is not absolutely necessary. Prefer using one Shape item with multiple + ShapePath elements over multiple Shape items. Scenes that cannot avoid + using a large number of individual Shape items should consider setting + Shape.vendorExtensionsEnabled to \c false. + \endlist + + \sa {Qt Quick Examples - Shapes}, Path, PathMove, PathLine, PathQuad, PathCubic, PathArc, PathSvg +*/ + +QQuickShapePrivate::QQuickShapePrivate() + : effectRefCount(0) +{ +} + +QQuickShapePrivate::~QQuickShapePrivate() +{ + delete renderer; +} + +void QQuickShapePrivate::_q_shapePathChanged() +{ + Q_Q(QQuickShape); + spChanged = true; + q->polish(); +} + +void QQuickShapePrivate::setStatus(QQuickShape::Status newStatus) +{ + Q_Q(QQuickShape); + if (status != newStatus) { + status = newStatus; + emit q->statusChanged(); + } +} + +struct QQuickShapeResourceInitializer +{ + QQuickShapeResourceInitializer() + { +#if defined(QT_STATIC) + Q_INIT_RESOURCE(qtquickshapes); +#endif + } +}; + +Q_GLOBAL_STATIC(QQuickShapeResourceInitializer, initQQuickShapeResources) + +QQuickShape::QQuickShape(QQuickItem *parent) + : QQuickItem(*(new QQuickShapePrivate), parent) +{ + initQQuickShapeResources(); + setFlag(ItemHasContents); +} + +QQuickShape::~QQuickShape() +{ +} + +/*! + \qmlproperty enumeration QtQuick.Shapes::Shape::rendererType + + This property determines which path rendering backend is active. + + \value Shape.UnknownRenderer + The renderer is unknown. + + \value Shape.GeometryRenderer + The generic, driver independent solution for OpenGL. Uses the same + CPU-based triangulation approach as QPainter's OpenGL 2 paint + engine. This is the default on non-NVIDIA hardware when the default, + OpenGL Qt Quick scenegraph backend is in use. + + \value Shape.NvprRenderer + Path items are rendered by performing OpenGL calls using the + \c{GL_NV_path_rendering} extension. This is the default on NVIDIA + hardware when the default, OpenGL Qt Quick scenegraph backend is in + use. + + \value Shape.SoftwareRenderer + Pure QPainter drawing using the raster paint engine. This is the + default, and only, option when the Qt Quick scenegraph is running + with the \c software backend. +*/ + +QQuickShape::RendererType QQuickShape::rendererType() const +{ + Q_D(const QQuickShape); + return d->rendererType; +} + +/*! + \qmlproperty bool QtQuick.Shapes::Shape::asynchronous + + When rendererType is \c Shape.GeometryRenderer, the input path is + triangulated on the CPU during the polishing phase of the Shape. This is + potentially expensive. To offload this work to separate worker threads, + set this property to \c true. + + When enabled, making a Shape visible will not wait for the content to + become available. Instead, the gui/main thread is not blocked and the + results of the path rendering are shown only when all the asynchronous + work has been finished. + + The default value is \c false. + */ + +bool QQuickShape::asynchronous() const +{ + Q_D(const QQuickShape); + return d->async; +} + +void QQuickShape::setAsynchronous(bool async) +{ + Q_D(QQuickShape); + if (d->async != async) { + d->async = async; + emit asynchronousChanged(); + if (d->componentComplete) + d->_q_shapePathChanged(); + } +} + +/*! + \qmlproperty bool QtQuick.Shapes::Shape::vendorExtensionsEnabled + + This property controls the usage of non-standard OpenGL extensions like + \c GL_NV_path_rendering. To disable Shape.NvprRenderer and force a uniform + behavior regardless of the graphics card and drivers, set this property to + \c false. + + The default value is \c true. + */ + +bool QQuickShape::vendorExtensionsEnabled() const +{ + Q_D(const QQuickShape); + return d->enableVendorExts; +} + +void QQuickShape::setVendorExtensionsEnabled(bool enable) +{ + Q_D(QQuickShape); + if (d->enableVendorExts != enable) { + d->enableVendorExts = enable; + emit vendorExtensionsEnabledChanged(); + } +} + +/*! + \qmlproperty enumeration QtQuick.Shapes::Shape::status + + This property determines the status of the Shape and is relevant when + Shape.asynchronous is set to \c true. + + \value Shape.Null + Not yet initialized. + + \value Shape.Ready + The Shape has finished processing. + + \value Shape.Processing + The path is being processed. + */ + +QQuickShape::Status QQuickShape::status() const +{ + Q_D(const QQuickShape); + return d->status; +} + +/*! + \qmlproperty enumeration QtQuick.Shapes::Shape::containsMode + \since QtQuick.Shapes 1.11 + + This property determines the definition of \l {QQuickItem::contains()}{contains()} + for the Shape. It is useful in case you add + \l {Qt Quick Pointer Handlers QML Types}{Pointer Handlers} and you + want to react only when the mouse or touchpoint is fully inside the Shape. + + \value Shape.BoundingRectContains + The default implementation of \l QQuickItem::contains() checks only + whether the given point is inside the rectangular bounding box. This is + the most efficient implementation, which is why it's the default. + + \value Shape.FillContains + Check whether the interior (the part that would be filled if you are + rendering it with fill) of any \l ShapePath that makes up this Shape + contains the given point. The more complex and numerous ShapePaths you + add, the less efficient this is to check, which can potentially slow + down event delivery in your application. So it should be used with care. + + One way to speed up the \c FillContains check is to generate an approximate + outline with as few points as possible, place that in a transparent Shape + on top, and add your Pointer Handlers to that, so that the containment + check is cheaper during event delivery. +*/ +QQuickShape::ContainsMode QQuickShape::containsMode() const +{ + Q_D(const QQuickShape); + return d->containsMode; +} + +void QQuickShape::setContainsMode(QQuickShape::ContainsMode containsMode) +{ + Q_D(QQuickShape); + if (d->containsMode == containsMode) + return; + + d->containsMode = containsMode; + emit containsModeChanged(); +} + +bool QQuickShape::contains(const QPointF &point) const +{ + Q_D(const QQuickShape); + switch (d->containsMode) { + case BoundingRectContains: + return QQuickItem::contains(point); + case FillContains: + for (QQuickShapePath *path : d->sp) { + if (path->path().contains(point)) + return true; + } + } + return false; +} + +static void vpe_append(QQmlListProperty *property, QObject *obj) +{ + QQuickShape *item = static_cast(property->object); + QQuickShapePrivate *d = QQuickShapePrivate::get(item); + QQuickShapePath *path = qobject_cast(obj); + if (path) + d->sp.append(path); + + QQuickItemPrivate::data_append(property, obj); + + if (path && d->componentComplete) { + QObject::connect(path, SIGNAL(shapePathChanged()), item, SLOT(_q_shapePathChanged())); + d->_q_shapePathChanged(); + } +} + +static void vpe_clear(QQmlListProperty *property) +{ + QQuickShape *item = static_cast(property->object); + QQuickShapePrivate *d = QQuickShapePrivate::get(item); + + for (QQuickShapePath *p : d->sp) + QObject::disconnect(p, SIGNAL(shapePathChanged()), item, SLOT(_q_shapePathChanged())); + + d->sp.clear(); + + QQuickItemPrivate::data_clear(property); + + if (d->componentComplete) + d->_q_shapePathChanged(); +} + +/*! + \qmlproperty list QtQuick.Shapes::Shape::data + + This property holds the ShapePath objects that define the contents of the + Shape. It can also contain any other type of objects, since Shape, like + Item, allows adding any visual or non-visual objects as children. + + \default + */ + +QQmlListProperty QQuickShape::data() +{ + return QQmlListProperty(this, + nullptr, + vpe_append, + QQuickItemPrivate::data_count, + QQuickItemPrivate::data_at, + vpe_clear); +} + +void QQuickShape::classBegin() +{ + QQuickItem::classBegin(); +} + +void QQuickShape::componentComplete() +{ + Q_D(QQuickShape); + + QQuickItem::componentComplete(); + + for (QQuickShapePath *p : d->sp) + connect(p, SIGNAL(shapePathChanged()), this, SLOT(_q_shapePathChanged())); + + d->_q_shapePathChanged(); +} + +void QQuickShape::updatePolish() +{ + Q_D(QQuickShape); + + const int currentEffectRefCount = d->extra.isAllocated() ? d->extra->recursiveEffectRefCount : 0; + if (!d->spChanged && currentEffectRefCount <= d->effectRefCount) + return; + + d->spChanged = false; + d->effectRefCount = currentEffectRefCount; + + if (!d->renderer) { + d->createRenderer(); + if (!d->renderer) + return; + emit rendererChanged(); + } + + // endSync() is where expensive calculations may happen (or get kicked off + // on worker threads), depending on the backend. Therefore do this only + // when the item is visible. + if (isVisible() || d->effectRefCount > 0) + d->sync(); + + update(); +} + +void QQuickShape::itemChange(ItemChange change, const ItemChangeData &data) +{ + Q_D(QQuickShape); + + // sync may have been deferred; do it now if the item became visible + if (change == ItemVisibleHasChanged && data.boolValue) + d->_q_shapePathChanged(); + + QQuickItem::itemChange(change, data); +} + +QSGNode *QQuickShape::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) +{ + // Called on the render thread, with the gui thread blocked. We can now + // safely access gui thread data. + + Q_D(QQuickShape); + if (d->renderer) { + if (!node) + node = d->createNode(); + d->renderer->updateNode(); + } + return node; +} + +// the renderer object lives on the gui thread +void QQuickShapePrivate::createRenderer() +{ + Q_Q(QQuickShape); + QSGRendererInterface *ri = q->window()->rendererInterface(); + if (!ri) + return; + + switch (ri->graphicsApi()) { +#if QT_CONFIG(opengl) + case QSGRendererInterface::OpenGL: + if (enableVendorExts && QQuickShapeNvprRenderNode::isSupported()) { + rendererType = QQuickShape::NvprRenderer; + renderer = new QQuickShapeNvprRenderer; + } else { + rendererType = QQuickShape::GeometryRenderer; + renderer = new QQuickShapeGenericRenderer(q); + } + break; +#endif + case QSGRendererInterface::Software: + rendererType = QQuickShape::SoftwareRenderer; + renderer = new QQuickShapeSoftwareRenderer; + break; + default: + qWarning("No path backend for this graphics API yet"); + break; + } +} + +// the node lives on the render thread +QSGNode *QQuickShapePrivate::createNode() +{ + Q_Q(QQuickShape); + QSGNode *node = nullptr; + if (!q->window()) + return node; + QSGRendererInterface *ri = q->window()->rendererInterface(); + if (!ri) + return node; + + switch (ri->graphicsApi()) { +#if QT_CONFIG(opengl) + case QSGRendererInterface::OpenGL: + if (enableVendorExts && QQuickShapeNvprRenderNode::isSupported()) { + node = new QQuickShapeNvprRenderNode; + static_cast(renderer)->setNode( + static_cast(node)); + } else { + node = new QQuickShapeGenericNode; + static_cast(renderer)->setRootNode( + static_cast(node)); + } + break; +#endif + case QSGRendererInterface::Software: + node = new QQuickShapeSoftwareRenderNode(q); + static_cast(renderer)->setNode( + static_cast(node)); + break; + default: + qWarning("No path backend for this graphics API yet"); + break; + } + + return node; +} + +void QQuickShapePrivate::asyncShapeReady(void *data) +{ + QQuickShapePrivate *self = static_cast(data); + self->setStatus(QQuickShape::Ready); + if (self->syncTimingActive) + qDebug("[Shape %p] [%d] [dirty=0x%x] async update took %lld ms", + self->q_func(), self->syncTimeCounter, self->syncTimingTotalDirty, self->syncTimer.elapsed()); +} + +void QQuickShapePrivate::sync() +{ + syncTimingTotalDirty = 0; + syncTimingActive = QQSHAPE_LOG_TIME_DIRTY_SYNC().isDebugEnabled(); + if (syncTimingActive) + syncTimer.start(); + + const bool useAsync = async && renderer->flags().testFlag(QQuickAbstractPathRenderer::SupportsAsync); + if (useAsync) { + setStatus(QQuickShape::Processing); + renderer->setAsyncCallback(asyncShapeReady, this); + } + + const int count = sp.count(); + renderer->beginSync(count); + + for (int i = 0; i < count; ++i) { + QQuickShapePath *p = sp[i]; + int &dirty(QQuickShapePathPrivate::get(p)->dirty); + syncTimingTotalDirty |= dirty; + + if (dirty & QQuickShapePathPrivate::DirtyPath) + renderer->setPath(i, p); + if (dirty & QQuickShapePathPrivate::DirtyStrokeColor) + renderer->setStrokeColor(i, p->strokeColor()); + if (dirty & QQuickShapePathPrivate::DirtyStrokeWidth) + renderer->setStrokeWidth(i, p->strokeWidth()); + if (dirty & QQuickShapePathPrivate::DirtyFillColor) + renderer->setFillColor(i, p->fillColor()); + if (dirty & QQuickShapePathPrivate::DirtyFillRule) + renderer->setFillRule(i, p->fillRule()); + if (dirty & QQuickShapePathPrivate::DirtyStyle) { + renderer->setJoinStyle(i, p->joinStyle(), p->miterLimit()); + renderer->setCapStyle(i, p->capStyle()); + } + if (dirty & QQuickShapePathPrivate::DirtyDash) + renderer->setStrokeStyle(i, p->strokeStyle(), p->dashOffset(), p->dashPattern()); + if (dirty & QQuickShapePathPrivate::DirtyFillGradient) + renderer->setFillGradient(i, p->fillGradient()); + + dirty = 0; + } + + if (syncTimingTotalDirty) + ++syncTimeCounter; + else + syncTimingActive = false; + + renderer->endSync(useAsync); + + if (!useAsync) { + setStatus(QQuickShape::Ready); + if (syncTimingActive) + qDebug("[Shape %p] [%d] [dirty=0x%x] update took %lld ms", + q_func(), syncTimeCounter, syncTimingTotalDirty, syncTimer.elapsed()); + } +} + +// ***** gradient support ***** + +/*! + \qmltype ShapeGradient + \instantiates QQuickShapeGradient + \inqmlmodule QtQuick.Shapes + \ingroup qtquick-paths + \ingroup qtquick-views + \inherits Gradient + \brief Base type of Shape fill gradients. + \since 5.10 + + This is an abstract base class for gradients like LinearGradient and + cannot be created directly. It extends \l Gradient with properties like the + spread mode. + */ + +QQuickShapeGradient::QQuickShapeGradient(QObject *parent) + : QQuickGradient(parent), + m_spread(PadSpread) +{ +} + +/*! + \qmlproperty enumeration QtQuick.Shapes::ShapeGradient::spread + + Specifies how the area outside the gradient area should be filled. The + default value is \c ShapeGradient.PadSpread. + + \value ShapeGradient.PadSpread + The area is filled with the closest stop color. + + \value ShapeGradient.RepeatSpread + The gradient is repeated outside the gradient area. + + \value ShapeGradient.ReflectSpread + The gradient is reflected outside the gradient area. + */ + +QQuickShapeGradient::SpreadMode QQuickShapeGradient::spread() const +{ + return m_spread; +} + +void QQuickShapeGradient::setSpread(SpreadMode mode) +{ + if (m_spread != mode) { + m_spread = mode; + emit spreadChanged(); + emit updated(); + } +} + +/*! + \qmltype LinearGradient + \instantiates QQuickShapeLinearGradient + \inqmlmodule QtQuick.Shapes + \ingroup qtquick-paths + \ingroup qtquick-views + \inherits ShapeGradient + \brief Linear gradient. + \since 5.10 + + Linear gradients interpolate colors between start and end points in Shape + items. Outside these points the gradient is either padded, reflected or + repeated depending on the spread type. + + \note LinearGradient is only supported in combination with Shape items. It + is not compatible with \l Rectangle, as that only supports \l Gradient. + + \sa QLinearGradient + */ + +QQuickShapeLinearGradient::QQuickShapeLinearGradient(QObject *parent) + : QQuickShapeGradient(parent) +{ +} + +/*! + \qmlproperty real QtQuick.Shapes::LinearGradient::x1 + \qmlproperty real QtQuick.Shapes::LinearGradient::y1 + \qmlproperty real QtQuick.Shapes::LinearGradient::x2 + \qmlproperty real QtQuick.Shapes::LinearGradient::y2 + + These properties define the start and end points between which color + interpolation occurs. By default both points are set to (0, 0). + */ + +qreal QQuickShapeLinearGradient::x1() const +{ + return m_start.x(); +} + +void QQuickShapeLinearGradient::setX1(qreal v) +{ + if (m_start.x() != v) { + m_start.setX(v); + emit x1Changed(); + emit updated(); + } +} + +qreal QQuickShapeLinearGradient::y1() const +{ + return m_start.y(); +} + +void QQuickShapeLinearGradient::setY1(qreal v) +{ + if (m_start.y() != v) { + m_start.setY(v); + emit y1Changed(); + emit updated(); + } +} + +qreal QQuickShapeLinearGradient::x2() const +{ + return m_end.x(); +} + +void QQuickShapeLinearGradient::setX2(qreal v) +{ + if (m_end.x() != v) { + m_end.setX(v); + emit x2Changed(); + emit updated(); + } +} + +qreal QQuickShapeLinearGradient::y2() const +{ + return m_end.y(); +} + +void QQuickShapeLinearGradient::setY2(qreal v) +{ + if (m_end.y() != v) { + m_end.setY(v); + emit y2Changed(); + emit updated(); + } +} + +/*! + \qmltype RadialGradient + \instantiates QQuickShapeRadialGradient + \inqmlmodule QtQuick.Shapes + \ingroup qtquick-paths + \ingroup qtquick-views + \inherits ShapeGradient + \brief Radial gradient. + \since 5.10 + + Radial gradients interpolate colors between a focal circle and a center + circle in Shape items. Points outside the cone defined by the two circles + will be transparent. + + Outside the end points the gradient is either padded, reflected or repeated + depending on the spread type. + + Below is an example of a simple radial gradient. Here the colors are + interpolated between the specified point and the end points on a circle + specified by the radius: + + \code + fillGradient: RadialGradient { + centerX: 50; centerY: 50 + centerRadius: 100 + focalX: centerX; focalY: centerY + GradientStop { position: 0; color: "blue" } + GradientStop { position: 0.2; color: "green" } + GradientStop { position: 0.4; color: "red" } + GradientStop { position: 0.6; color: "yellow" } + GradientStop { position: 1; color: "cyan" } + } + \endcode + + \image shape-radial-gradient.png + + Extended radial gradients, where a separate focal circle is specified, are + also supported. + + \note RadialGradient is only supported in combination with Shape items. It + is not compatible with \l Rectangle, as that only supports \l Gradient. + + \sa QRadialGradient + */ + +QQuickShapeRadialGradient::QQuickShapeRadialGradient(QObject *parent) + : QQuickShapeGradient(parent) +{ +} + +/*! + \qmlproperty real QtQuick.Shapes::RadialGradient::centerX + \qmlproperty real QtQuick.Shapes::RadialGradient::centerY + \qmlproperty real QtQuick.Shapes::RadialGradient::focalX + \qmlproperty real QtQuick.Shapes::RadialGradient::focalY + + These properties define the center and focal points. To specify a simple + radial gradient, set focalX and focalY to the value of centerX and + centerY, respectively. + */ + +qreal QQuickShapeRadialGradient::centerX() const +{ + return m_centerPoint.x(); +} + +void QQuickShapeRadialGradient::setCenterX(qreal v) +{ + if (m_centerPoint.x() != v) { + m_centerPoint.setX(v); + emit centerXChanged(); + emit updated(); + } +} + +qreal QQuickShapeRadialGradient::centerY() const +{ + return m_centerPoint.y(); +} + +void QQuickShapeRadialGradient::setCenterY(qreal v) +{ + if (m_centerPoint.y() != v) { + m_centerPoint.setY(v); + emit centerYChanged(); + emit updated(); + } +} + +/*! + \qmlproperty real QtQuick.Shapes::RadialGradient::centerRadius + \qmlproperty real QtQuick.Shapes::RadialGradient::focalRadius + + These properties define the center and focal radius. For simple radial + gradients, focalRadius should be set to \c 0 (the default value). + */ + +qreal QQuickShapeRadialGradient::centerRadius() const +{ + return m_centerRadius; +} + +void QQuickShapeRadialGradient::setCenterRadius(qreal v) +{ + if (m_centerRadius != v) { + m_centerRadius = v; + emit centerRadiusChanged(); + emit updated(); + } +} + +qreal QQuickShapeRadialGradient::focalX() const +{ + return m_focalPoint.x(); +} + +void QQuickShapeRadialGradient::setFocalX(qreal v) +{ + if (m_focalPoint.x() != v) { + m_focalPoint.setX(v); + emit focalXChanged(); + emit updated(); + } +} + +qreal QQuickShapeRadialGradient::focalY() const +{ + return m_focalPoint.y(); +} + +void QQuickShapeRadialGradient::setFocalY(qreal v) +{ + if (m_focalPoint.y() != v) { + m_focalPoint.setY(v); + emit focalYChanged(); + emit updated(); + } +} + +qreal QQuickShapeRadialGradient::focalRadius() const +{ + return m_focalRadius; +} + +void QQuickShapeRadialGradient::setFocalRadius(qreal v) +{ + if (m_focalRadius != v) { + m_focalRadius = v; + emit focalRadiusChanged(); + emit updated(); + } +} + +/*! + \qmltype ConicalGradient + \instantiates QQuickShapeConicalGradient + \inqmlmodule QtQuick.Shapes + \ingroup qtquick-paths + \ingroup qtquick-views + \inherits ShapeGradient + \brief Conical gradient. + \since 5.10 + + Conical gradients interpolate colors counter-clockwise around a center + point in Shape items. + + \note The \l{ShapeGradient::spread}{spread mode} setting has no effect for + conical gradients. + + \note ConicalGradient is only supported in combination with Shape items. It + is not compatible with \l Rectangle, as that only supports \l Gradient. + + \sa QConicalGradient + */ + +QQuickShapeConicalGradient::QQuickShapeConicalGradient(QObject *parent) + : QQuickShapeGradient(parent) +{ +} + +/*! + \qmlproperty real QtQuick.Shapes::ConicalGradient::centerX + \qmlproperty real QtQuick.Shapes::ConicalGradient::centerY + + These properties define the center point of the conical gradient. + */ + +qreal QQuickShapeConicalGradient::centerX() const +{ + return m_centerPoint.x(); +} + +void QQuickShapeConicalGradient::setCenterX(qreal v) +{ + if (m_centerPoint.x() != v) { + m_centerPoint.setX(v); + emit centerXChanged(); + emit updated(); + } +} + +qreal QQuickShapeConicalGradient::centerY() const +{ + return m_centerPoint.y(); +} + +void QQuickShapeConicalGradient::setCenterY(qreal v) +{ + if (m_centerPoint.y() != v) { + m_centerPoint.setY(v); + emit centerYChanged(); + emit updated(); + } +} + +/*! + \qmlproperty real QtQuick.Shapes::ConicalGradient::angle + + This property defines the start angle for the conical gradient. The value + is in degrees (0-360). + */ + +qreal QQuickShapeConicalGradient::angle() const +{ + return m_angle; +} + +void QQuickShapeConicalGradient::setAngle(qreal v) +{ + if (m_angle != v) { + m_angle = v; + emit angleChanged(); + emit updated(); + } +} + +#if QT_CONFIG(opengl) + +// contexts sharing with each other get the same cache instance +class QQuickShapeGradientCacheWrapper +{ +public: + QQuickShapeGradientCache *get(QOpenGLContext *context) + { + return m_resource.value(context); + } + +private: + QOpenGLMultiGroupSharedResource m_resource; +}; + +QQuickShapeGradientCache *QQuickShapeGradientCache::currentCache() +{ + static QQuickShapeGradientCacheWrapper qt_path_gradient_caches; + return qt_path_gradient_caches.get(QOpenGLContext::currentContext()); +} + +// let QOpenGLContext manage the lifetime of the cached textures +QQuickShapeGradientCache::~QQuickShapeGradientCache() +{ + m_cache.clear(); +} + +void QQuickShapeGradientCache::invalidateResource() +{ + m_cache.clear(); +} + +void QQuickShapeGradientCache::freeResource(QOpenGLContext *) +{ + qDeleteAll(m_cache); + m_cache.clear(); +} + +static void generateGradientColorTable(const QQuickShapeGradientCache::Key &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 *QQuickShapeGradientCache::get(const Key &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 QQuickShapeGradient::PadSpread: + tx->setHorizontalWrapMode(QSGTexture::ClampToEdge); + tx->setVerticalWrapMode(QSGTexture::ClampToEdge); + break; + case QQuickShapeGradient::RepeatSpread: + tx->setHorizontalWrapMode(QSGTexture::Repeat); + tx->setVerticalWrapMode(QSGTexture::Repeat); + break; + case QQuickShapeGradient::ReflectSpread: + tx->setHorizontalWrapMode(QSGTexture::MirroredRepeat); + tx->setVerticalWrapMode(QSGTexture::MirroredRepeat); + break; + default: + qWarning("Unknown gradient spread mode %d", grad.spread); + break; + } + tx->setFiltering(QSGTexture::Linear); + m_cache[grad] = tx; + } + return tx; +} + +#endif // QT_CONFIG(opengl) + +QT_END_NAMESPACE + +#include "moc_qquickshape_p.cpp" diff --git a/src/quickshapes/qquickshape_p.h b/src/quickshapes/qquickshape_p.h new file mode 100644 index 0000000000..cd242cafc3 --- /dev/null +++ b/src/quickshapes/qquickshape_p.h @@ -0,0 +1,377 @@ +/**************************************************************************** +** +** 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 QQUICKSHAPE_P_H +#define QQUICKSHAPE_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 +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickShapePathPrivate; +class QQuickShapePrivate; + +class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeGradient : public QQuickGradient +{ + Q_OBJECT + Q_PROPERTY(SpreadMode spread READ spread WRITE setSpread NOTIFY spreadChanged) + Q_CLASSINFO("DefaultProperty", "stops") + +public: + enum SpreadMode { + PadSpread, + RepeatSpread, + ReflectSpread + }; + Q_ENUM(SpreadMode) + + QQuickShapeGradient(QObject *parent = nullptr); + + SpreadMode spread() const; + void setSpread(SpreadMode mode); + +signals: + void spreadChanged(); + +private: + SpreadMode m_spread; +}; + +class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeLinearGradient : public QQuickShapeGradient +{ + 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: + QQuickShapeLinearGradient(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_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeRadialGradient : public QQuickShapeGradient +{ + Q_OBJECT + Q_PROPERTY(qreal centerX READ centerX WRITE setCenterX NOTIFY centerXChanged) + Q_PROPERTY(qreal centerY READ centerY WRITE setCenterY NOTIFY centerYChanged) + Q_PROPERTY(qreal centerRadius READ centerRadius WRITE setCenterRadius NOTIFY centerRadiusChanged) + Q_PROPERTY(qreal focalX READ focalX WRITE setFocalX NOTIFY focalXChanged) + Q_PROPERTY(qreal focalY READ focalY WRITE setFocalY NOTIFY focalYChanged) + Q_PROPERTY(qreal focalRadius READ focalRadius WRITE setFocalRadius NOTIFY focalRadiusChanged) + Q_CLASSINFO("DefaultProperty", "stops") + +public: + QQuickShapeRadialGradient(QObject *parent = nullptr); + + qreal centerX() const; + void setCenterX(qreal v); + + qreal centerY() const; + void setCenterY(qreal v); + + qreal centerRadius() const; + void setCenterRadius(qreal v); + + qreal focalX() const; + void setFocalX(qreal v); + + qreal focalY() const; + void setFocalY(qreal v); + + qreal focalRadius() const; + void setFocalRadius(qreal v); + +signals: + void centerXChanged(); + void centerYChanged(); + void focalXChanged(); + void focalYChanged(); + void centerRadiusChanged(); + void focalRadiusChanged(); + +private: + QPointF m_centerPoint; + QPointF m_focalPoint; + qreal m_centerRadius = 0; + qreal m_focalRadius = 0; +}; + +class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapeConicalGradient : public QQuickShapeGradient +{ + Q_OBJECT + Q_PROPERTY(qreal centerX READ centerX WRITE setCenterX NOTIFY centerXChanged) + Q_PROPERTY(qreal centerY READ centerY WRITE setCenterY NOTIFY centerYChanged) + Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged) + Q_CLASSINFO("DefaultProperty", "stops") + +public: + QQuickShapeConicalGradient(QObject *parent = nullptr); + + qreal centerX() const; + void setCenterX(qreal v); + + qreal centerY() const; + void setCenterY(qreal v); + + qreal angle() const; + void setAngle(qreal v); + +signals: + void centerXChanged(); + void centerYChanged(); + void angleChanged(); + +private: + QPointF m_centerPoint; + qreal m_angle = 0; +}; + +class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapePath : public QQuickPath +{ + Q_OBJECT + + 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 dashPattern READ dashPattern WRITE setDashPattern NOTIFY dashPatternChanged) + Q_PROPERTY(QQuickShapeGradient *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) + + QQuickShapePath(QObject *parent = nullptr); + ~QQuickShapePath(); + + 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 dashPattern() const; + void setDashPattern(const QVector &array); + + QQuickShapeGradient *fillGradient() const; + void setFillGradient(QQuickShapeGradient *gradient); + void resetFillGradient(); + +Q_SIGNALS: + void shapePathChanged(); + void strokeColorChanged(); + void strokeWidthChanged(); + void fillColorChanged(); + void fillRuleChanged(); + void joinStyleChanged(); + void miterLimitChanged(); + void capStyleChanged(); + void strokeStyleChanged(); + void dashOffsetChanged(); + void dashPatternChanged(); + +private: + Q_DISABLE_COPY(QQuickShapePath) + Q_DECLARE_PRIVATE(QQuickShapePath) + Q_PRIVATE_SLOT(d_func(), void _q_fillGradientChanged()) +}; + +class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShape : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(RendererType rendererType READ rendererType NOTIFY rendererChanged) + Q_PROPERTY(bool asynchronous READ asynchronous WRITE setAsynchronous NOTIFY asynchronousChanged) + Q_PROPERTY(bool vendorExtensionsEnabled READ vendorExtensionsEnabled WRITE setVendorExtensionsEnabled NOTIFY vendorExtensionsEnabledChanged) + Q_PROPERTY(Status status READ status NOTIFY statusChanged) + Q_PROPERTY(ContainsMode containsMode READ containsMode WRITE setContainsMode NOTIFY containsModeChanged REVISION 11) + Q_PROPERTY(QQmlListProperty data READ data) + Q_CLASSINFO("DefaultProperty", "data") + +public: + enum RendererType { + UnknownRenderer, + GeometryRenderer, + NvprRenderer, + SoftwareRenderer + }; + Q_ENUM(RendererType) + + enum Status { + Null, + Ready, + Processing + }; + Q_ENUM(Status) + + enum ContainsMode { + BoundingRectContains, + FillContains + }; + Q_ENUM(ContainsMode) + + QQuickShape(QQuickItem *parent = nullptr); + ~QQuickShape(); + + RendererType rendererType() const; + + bool asynchronous() const; + void setAsynchronous(bool async); + + bool vendorExtensionsEnabled() const; + void setVendorExtensionsEnabled(bool enable); + + Status status() const; + + ContainsMode containsMode() const; + void setContainsMode(ContainsMode containsMode); + + bool contains(const QPointF &point) const override; + + QQmlListProperty data(); + +protected: + QSGNode *updatePaintNode(QSGNode *node, UpdatePaintNodeData *) override; + void updatePolish() override; + void itemChange(ItemChange change, const ItemChangeData &data) override; + void componentComplete() override; + void classBegin() override; + +Q_SIGNALS: + void rendererChanged(); + void asynchronousChanged(); + void vendorExtensionsEnabledChanged(); + void statusChanged(); + Q_REVISION(11) void containsModeChanged(); + +private: + Q_DISABLE_COPY(QQuickShape) + Q_DECLARE_PRIVATE(QQuickShape) + Q_PRIVATE_SLOT(d_func(), void _q_shapePathChanged()) +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickShape) + +#endif // QQUICKSHAPE_P_H diff --git a/src/quickshapes/qquickshape_p_p.h b/src/quickshapes/qquickshape_p_p.h new file mode 100644 index 0000000000..bf4a47f62c --- /dev/null +++ b/src/quickshapes/qquickshape_p_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 QQUICKSHAPE_P_P_H +#define QQUICKSHAPE_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 +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QSGPlainTexture; + +class QQuickAbstractPathRenderer +{ +public: + enum Flag { + SupportsAsync = 0x01 + }; + Q_DECLARE_FLAGS(Flags, Flag) + + enum FillGradientType { NoGradient = 0, LinearGradient, RadialGradient, ConicalGradient }; + struct GradientDesc { // can fully describe a linear/radial/conical gradient + QGradientStops stops; + QQuickShapeGradient::SpreadMode spread; + QPointF a; // start (L) or center point (R/C) + QPointF b; // end (L) or focal point (R) + qreal v0; // center radius (R) or start angle (C) + qreal v1; // focal radius (R) + }; + + virtual ~QQuickAbstractPathRenderer() { } + + // Gui thread + virtual void beginSync(int totalCount) = 0; + virtual void endSync(bool async) = 0; + virtual void setAsyncCallback(void (*)(void *), void *) { } + virtual Flags flags() const { return 0; } + virtual void setPath(int index, const QQuickPath *path) = 0; + virtual void setStrokeColor(int index, const QColor &color) = 0; + virtual void setStrokeWidth(int index, qreal w) = 0; + virtual void setFillColor(int index, const QColor &color) = 0; + virtual void setFillRule(int index, QQuickShapePath::FillRule fillRule) = 0; + virtual void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) = 0; + virtual void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) = 0; + virtual void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, + qreal dashOffset, const QVector &dashPattern) = 0; + virtual void setFillGradient(int index, QQuickShapeGradient *gradient) = 0; + + // Render thread, with gui blocked + virtual void updateNode() = 0; +}; + +Q_DECLARE_OPERATORS_FOR_FLAGS(QQuickAbstractPathRenderer::Flags) + +struct QQuickShapeStrokeFillParams +{ + QQuickShapeStrokeFillParams(); + + QColor strokeColor; + qreal strokeWidth; + QColor fillColor; + QQuickShapePath::FillRule fillRule; + QQuickShapePath::JoinStyle joinStyle; + int miterLimit; + QQuickShapePath::CapStyle capStyle; + QQuickShapePath::StrokeStyle strokeStyle; + qreal dashOffset; + QVector dashPattern; + QQuickShapeGradient *fillGradient; +}; + +class Q_QUICKSHAPES_PRIVATE_EXPORT QQuickShapePathPrivate : public QQuickPathPrivate +{ + Q_DECLARE_PUBLIC(QQuickShapePath) + +public: + enum Dirty { + DirtyPath = 0x01, + DirtyStrokeColor = 0x02, + DirtyStrokeWidth = 0x04, + DirtyFillColor = 0x08, + DirtyFillRule = 0x10, + DirtyStyle = 0x20, + DirtyDash = 0x40, + DirtyFillGradient = 0x80, + + DirtyAll = 0xFF + }; + + QQuickShapePathPrivate(); + + void _q_pathChanged(); + void _q_fillGradientChanged(); + + static QQuickShapePathPrivate *get(QQuickShapePath *p) { return p->d_func(); } + + int dirty; + QQuickShapeStrokeFillParams sfp; +}; + +class QQuickShapePrivate : public QQuickItemPrivate +{ + Q_DECLARE_PUBLIC(QQuickShape) + +public: + QQuickShapePrivate(); + ~QQuickShapePrivate(); + + void createRenderer(); + QSGNode *createNode(); + void sync(); + + void _q_shapePathChanged(); + void setStatus(QQuickShape::Status newStatus); + + static QQuickShapePrivate *get(QQuickShape *item) { return item->d_func(); } + + static void asyncShapeReady(void *data); + + int effectRefCount; + QVector sp; + QElapsedTimer syncTimer; + QQuickAbstractPathRenderer *renderer = nullptr; + int syncTimingTotalDirty = 0; + int syncTimeCounter = 0; + QQuickShape::Status status = QQuickShape::Null; + QQuickShape::RendererType rendererType = QQuickShape::UnknownRenderer; + QQuickShape::ContainsMode containsMode = QQuickShape::BoundingRectContains; + bool spChanged = false; + bool async = false; + bool enableVendorExts = true; + bool syncTimingActive = false; +}; + +#if QT_CONFIG(opengl) + +class QQuickShapeGradientCache : public QOpenGLSharedResource +{ +public: + struct Key { + Key(const QGradientStops &stops, QQuickShapeGradient::SpreadMode spread) + : stops(stops), spread(spread) + { } + QGradientStops stops; + QQuickShapeGradient::SpreadMode spread; + bool operator==(const Key &other) const + { + return spread == other.spread && stops == other.stops; + } + }; + + QQuickShapeGradientCache(QOpenGLContext *context) : QOpenGLSharedResource(context->shareGroup()) { } + ~QQuickShapeGradientCache(); + + void invalidateResource() override; + void freeResource(QOpenGLContext *) override; + + QSGTexture *get(const Key &grad); + + static QQuickShapeGradientCache *currentCache(); + +private: + QHash m_cache; +}; + +inline uint qHash(const QQuickShapeGradientCache::Key &v, uint seed = 0) +{ + uint h = seed + v.spread; + for (int i = 0; i < 3 && i < v.stops.count(); ++i) + h += v.stops[i].second.rgba(); + return h; +} + +#endif // QT_CONFIG(opengl) + +QT_END_NAMESPACE + +#endif diff --git a/src/quickshapes/qquickshapegenericrenderer.cpp b/src/quickshapes/qquickshapegenericrenderer.cpp new file mode 100644 index 0000000000..8a4785a83a --- /dev/null +++ b/src/quickshapes/qquickshapegenericrenderer.cpp @@ -0,0 +1,1007 @@ +/**************************************************************************** +** +** 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 "qquickshapegenericrenderer_p.h" +#include +#include +#include + +#if QT_CONFIG(opengl) +#include +#include +#include +#include +#endif + +QT_BEGIN_NAMESPACE + +static const qreal TRI_SCALE = 1; + +struct ColoredVertex // must match QSGGeometry::ColoredPoint2D +{ + float x, y; + QQuickShapeGenericRenderer::Color4ub color; + void set(float nx, float ny, QQuickShapeGenericRenderer::Color4ub ncolor) + { + x = nx; y = ny; color = ncolor; + } +}; + +static inline QQuickShapeGenericRenderer::Color4ub colorToColor4ub(const QColor &c) +{ + QQuickShapeGenericRenderer::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; +} + +QQuickShapeGenericStrokeFillNode::QQuickShapeGenericStrokeFillNode(QQuickWindow *window) + : m_material(nullptr) +{ + setFlag(QSGNode::OwnsGeometry, true); + setGeometry(new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), 0, 0)); + activateMaterial(window, MatSolidColor); +#ifdef QSG_RUNTIME_DESCRIPTION + qsgnode_set_description(this, QLatin1String("stroke-fill")); +#endif +} + +void QQuickShapeGenericStrokeFillNode::activateMaterial(QQuickWindow *window, 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. + m_material.reset(QQuickShapeGenericMaterialFactory::createVertexColor(window)); + break; + case MatLinearGradient: + m_material.reset(QQuickShapeGenericMaterialFactory::createLinearGradient(window, this)); + break; + case MatRadialGradient: + m_material.reset(QQuickShapeGenericMaterialFactory::createRadialGradient(window, this)); + break; + case MatConicalGradient: + m_material.reset(QQuickShapeGenericMaterialFactory::createConicalGradient(window, this)); + break; + default: + qWarning("Unknown material %d", m); + return; + } + + if (material() != m_material.data()) + setMaterial(m_material.data()); +} + +static bool q_supportsElementIndexUint(QSGRendererInterface::GraphicsApi api) +{ + static bool elementIndexUint = true; +#if QT_CONFIG(opengl) + if (api == QSGRendererInterface::OpenGL) { + static bool elementIndexUintChecked = false; + if (!elementIndexUintChecked) { + elementIndexUintChecked = true; + QOpenGLContext *context = QOpenGLContext::currentContext(); + QScopedPointer dummyContext; + QScopedPointer dummySurface; + bool ok = true; + if (!context) { + dummyContext.reset(new QOpenGLContext); + dummyContext->create(); + context = dummyContext.data(); + dummySurface.reset(new QOffscreenSurface); + dummySurface->setFormat(context->format()); + dummySurface->create(); + ok = context->makeCurrent(dummySurface.data()); + } + if (ok) { + elementIndexUint = static_cast(context->functions())->hasOpenGLExtension( + QOpenGLExtensions::ElementIndexUint); + } + } + } +#else + Q_UNUSED(api); +#endif + return elementIndexUint; +} + +QQuickShapeGenericRenderer::~QQuickShapeGenericRenderer() +{ + for (ShapePathData &d : m_sp) { + if (d.pendingFill) + d.pendingFill->orphaned = true; + if (d.pendingStroke) + d.pendingStroke->orphaned = true; + } +} + +// sync, and so triangulation too, happens on the gui thread +// - except when async is set, in which case triangulation is moved to worker threads + +void QQuickShapeGenericRenderer::beginSync(int totalCount) +{ + if (m_sp.count() != totalCount) { + m_sp.resize(totalCount); + m_accDirty |= DirtyList; + } + for (ShapePathData &d : m_sp) + d.syncDirty = 0; +} + +void QQuickShapeGenericRenderer::setPath(int index, const QQuickPath *path) +{ + ShapePathData &d(m_sp[index]); + d.path = path ? path->path() : QPainterPath(); + d.syncDirty |= DirtyFillGeom | DirtyStrokeGeom; +} + +void QQuickShapeGenericRenderer::setStrokeColor(int index, const QColor &color) +{ + ShapePathData &d(m_sp[index]); + d.strokeColor = colorToColor4ub(color); + d.syncDirty |= DirtyColor; +} + +void QQuickShapeGenericRenderer::setStrokeWidth(int index, qreal w) +{ + ShapePathData &d(m_sp[index]); + d.strokeWidth = w; + if (w >= 0.0f) + d.pen.setWidthF(w); + d.syncDirty |= DirtyStrokeGeom; +} + +void QQuickShapeGenericRenderer::setFillColor(int index, const QColor &color) +{ + ShapePathData &d(m_sp[index]); + d.fillColor = colorToColor4ub(color); + d.syncDirty |= DirtyColor; +} + +void QQuickShapeGenericRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule) +{ + ShapePathData &d(m_sp[index]); + d.fillRule = Qt::FillRule(fillRule); + d.syncDirty |= DirtyFillGeom; +} + +void QQuickShapeGenericRenderer::setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) +{ + ShapePathData &d(m_sp[index]); + d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle)); + d.pen.setMiterLimit(miterLimit); + d.syncDirty |= DirtyStrokeGeom; +} + +void QQuickShapeGenericRenderer::setCapStyle(int index, QQuickShapePath::CapStyle capStyle) +{ + ShapePathData &d(m_sp[index]); + d.pen.setCapStyle(Qt::PenCapStyle(capStyle)); + d.syncDirty |= DirtyStrokeGeom; +} + +void QQuickShapeGenericRenderer::setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, + qreal dashOffset, const QVector &dashPattern) +{ + ShapePathData &d(m_sp[index]); + d.pen.setStyle(Qt::PenStyle(strokeStyle)); + if (strokeStyle == QQuickShapePath::DashLine) { + d.pen.setDashPattern(dashPattern); + d.pen.setDashOffset(dashOffset); + } + d.syncDirty |= DirtyStrokeGeom; +} + +void QQuickShapeGenericRenderer::setFillGradient(int index, QQuickShapeGradient *gradient) +{ + ShapePathData &d(m_sp[index]); + if (gradient) { + d.fillGradient.stops = gradient->gradientStops(); // sorted + d.fillGradient.spread = gradient->spread(); + if (QQuickShapeLinearGradient *g = qobject_cast(gradient)) { + d.fillGradientActive = LinearGradient; + d.fillGradient.a = QPointF(g->x1(), g->y1()); + d.fillGradient.b = QPointF(g->x2(), g->y2()); + } else if (QQuickShapeRadialGradient *g = qobject_cast(gradient)) { + d.fillGradientActive = RadialGradient; + d.fillGradient.a = QPointF(g->centerX(), g->centerY()); + d.fillGradient.b = QPointF(g->focalX(), g->focalY()); + d.fillGradient.v0 = g->centerRadius(); + d.fillGradient.v1 = g->focalRadius(); + } else if (QQuickShapeConicalGradient *g = qobject_cast(gradient)) { + d.fillGradientActive = ConicalGradient; + d.fillGradient.a = QPointF(g->centerX(), g->centerY()); + d.fillGradient.v0 = g->angle(); + } else { + Q_UNREACHABLE(); + } + } else { + d.fillGradientActive = NoGradient; + } + d.syncDirty |= DirtyFillGradient; +} + +void QQuickShapeFillRunnable::run() +{ + QQuickShapeGenericRenderer::triangulateFill(path, fillColor, &fillVertices, &fillIndices, &indexType, supportsElementIndexUint); + emit done(this); +} + +void QQuickShapeStrokeRunnable::run() +{ + QQuickShapeGenericRenderer::triangulateStroke(path, pen, strokeColor, &strokeVertices, clipSize); + emit done(this); +} + +void QQuickShapeGenericRenderer::setAsyncCallback(void (*callback)(void *), void *data) +{ + m_asyncCallback = callback; + m_asyncCallbackData = data; +} + +static QThreadPool *pathWorkThreadPool = nullptr; + +static void deletePathWorkThreadPool() +{ + delete pathWorkThreadPool; + pathWorkThreadPool = nullptr; +} + +void QQuickShapeGenericRenderer::endSync(bool async) +{ + bool didKickOffAsync = false; + + for (int i = 0; i < m_sp.count(); ++i) { + ShapePathData &d(m_sp[i]); + if (!d.syncDirty) + continue; + + m_accDirty |= d.syncDirty; + + // 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 updateNode() + // on the render thread (with the gui thread blocked). For our purposes + // here syncDirty is still required since geometry regeneration must only + // happen when there was an actual change in this particular sync round. + d.effectiveDirty |= d.syncDirty; + + if (d.path.isEmpty()) { + d.fillVertices.clear(); + d.fillIndices.clear(); + d.strokeVertices.clear(); + continue; + } + + if (async && !pathWorkThreadPool) { + qAddPostRoutine(deletePathWorkThreadPool); + pathWorkThreadPool = new QThreadPool; + const int idealCount = QThread::idealThreadCount(); + pathWorkThreadPool->setMaxThreadCount(idealCount > 0 ? idealCount * 2 : 4); + } + + if ((d.syncDirty & DirtyFillGeom) && d.fillColor.a) { + d.path.setFillRule(d.fillRule); + if (m_api == QSGRendererInterface::Unknown) + m_api = m_item->window()->rendererInterface()->graphicsApi(); + if (async) { + QQuickShapeFillRunnable *r = new QQuickShapeFillRunnable; + r->setAutoDelete(false); + if (d.pendingFill) + d.pendingFill->orphaned = true; + d.pendingFill = r; + r->path = d.path; + r->fillColor = d.fillColor; + r->supportsElementIndexUint = q_supportsElementIndexUint(m_api); + // Unlikely in practice but in theory m_sp could be + // resized. Therefore, capture 'i' instead of 'd'. + QObject::connect(r, &QQuickShapeFillRunnable::done, qApp, [this, i](QQuickShapeFillRunnable *r) { + // Bail out when orphaned (meaning either another run was + // started after this one, or the renderer got destroyed). + if (!r->orphaned && i < m_sp.count()) { + ShapePathData &d(m_sp[i]); + d.fillVertices = r->fillVertices; + d.fillIndices = r->fillIndices; + d.indexType = r->indexType; + d.pendingFill = nullptr; + d.effectiveDirty |= DirtyFillGeom; + maybeUpdateAsyncItem(); + } + r->deleteLater(); + }); + didKickOffAsync = true; + pathWorkThreadPool->start(r); + } else { + triangulateFill(d.path, d.fillColor, &d.fillVertices, &d.fillIndices, &d.indexType, q_supportsElementIndexUint(m_api)); + } + } + + if ((d.syncDirty & DirtyStrokeGeom) && d.strokeWidth >= 0.0f && d.strokeColor.a) { + if (async) { + QQuickShapeStrokeRunnable *r = new QQuickShapeStrokeRunnable; + r->setAutoDelete(false); + if (d.pendingStroke) + d.pendingStroke->orphaned = true; + d.pendingStroke = r; + r->path = d.path; + r->pen = d.pen; + r->strokeColor = d.strokeColor; + r->clipSize = QSize(m_item->width(), m_item->height()); + QObject::connect(r, &QQuickShapeStrokeRunnable::done, qApp, [this, i](QQuickShapeStrokeRunnable *r) { + if (!r->orphaned && i < m_sp.count()) { + ShapePathData &d(m_sp[i]); + d.strokeVertices = r->strokeVertices; + d.pendingStroke = nullptr; + d.effectiveDirty |= DirtyStrokeGeom; + maybeUpdateAsyncItem(); + } + r->deleteLater(); + }); + didKickOffAsync = true; + pathWorkThreadPool->start(r); + } else { + triangulateStroke(d.path, d.pen, d.strokeColor, &d.strokeVertices, + QSize(m_item->width(), m_item->height())); + } + } + } + + if (!didKickOffAsync && async && m_asyncCallback) + m_asyncCallback(m_asyncCallbackData); +} + +void QQuickShapeGenericRenderer::maybeUpdateAsyncItem() +{ + for (const ShapePathData &d : qAsConst(m_sp)) { + if (d.pendingFill || d.pendingStroke) + return; + } + m_accDirty |= DirtyFillGeom | DirtyStrokeGeom; + m_item->update(); + if (m_asyncCallback) + m_asyncCallback(m_asyncCallbackData); +} + +// the stroke/fill triangulation functions may be invoked either on the gui +// thread or some worker thread and must thus be self-contained. +void QQuickShapeGenericRenderer::triangulateFill(const QPainterPath &path, + const Color4ub &fillColor, + VertexContainerType *fillVertices, + IndexContainerType *fillIndices, + QSGGeometry::Type *indexType, + bool supportsElementIndexUint) +{ + const QVectorPath &vp = qtVectorPathForPath(path); + + QTriangleSet ts = qTriangulate(vp, QTransform::fromScale(TRI_SCALE, TRI_SCALE), 1, supportsElementIndexUint); + const int vertexCount = ts.vertices.count() / 2; // just a qreal vector with x,y hence the / 2 + fillVertices->resize(vertexCount); + ColoredVertex *vdst = reinterpret_cast(fillVertices->data()); + const qreal *vsrc = ts.vertices.constData(); + for (int i = 0; i < vertexCount; ++i) + vdst[i].set(vsrc[i * 2] / TRI_SCALE, vsrc[i * 2 + 1] / TRI_SCALE, fillColor); + + size_t indexByteSize; + if (ts.indices.type() == QVertexIndexVector::UnsignedShort) { + *indexType = QSGGeometry::UnsignedShortType; + // fillIndices is still QVector. Just resize to N/2 and pack + // the N quint16s into it. + fillIndices->resize(ts.indices.size() / 2); + indexByteSize = ts.indices.size() * sizeof(quint16); + } else { + *indexType = QSGGeometry::UnsignedIntType; + fillIndices->resize(ts.indices.size()); + indexByteSize = ts.indices.size() * sizeof(quint32); + } + memcpy(fillIndices->data(), ts.indices.data(), indexByteSize); +} + +void QQuickShapeGenericRenderer::triangulateStroke(const QPainterPath &path, + const QPen &pen, + const Color4ub &strokeColor, + VertexContainerType *strokeVertices, + const QSize &clipSize) +{ + const QVectorPath &vp = qtVectorPathForPath(path); + const QRectF clip(QPointF(0, 0), clipSize); + const qreal inverseScale = 1.0 / TRI_SCALE; + + QTriangulatingStroker stroker; + stroker.setInvScale(inverseScale); + + if (pen.style() == Qt::SolidLine) { + stroker.process(vp, pen, clip, nullptr); + } else { + QDashedStrokeProcessor dashStroker; + dashStroker.setInvScale(inverseScale); + dashStroker.process(vp, pen, clip, nullptr); + QVectorPath dashStroke(dashStroker.points(), dashStroker.elementCount(), + dashStroker.elementTypes(), 0); + stroker.process(dashStroke, pen, clip, nullptr); + } + + if (!stroker.vertexCount()) { + strokeVertices->clear(); + return; + } + + const int vertexCount = stroker.vertexCount() / 2; // just a float vector with x,y hence the / 2 + strokeVertices->resize(vertexCount); + ColoredVertex *vdst = reinterpret_cast(strokeVertices->data()); + const float *vsrc = stroker.vertices(); + for (int i = 0; i < vertexCount; ++i) + vdst[i].set(vsrc[i * 2], vsrc[i * 2 + 1], strokeColor); +} + +void QQuickShapeGenericRenderer::setRootNode(QQuickShapeGenericNode *node) +{ + if (m_rootNode != node) { + m_rootNode = node; + m_accDirty |= DirtyList; + } +} + +// on the render thread with gui blocked +void QQuickShapeGenericRenderer::updateNode() +{ + if (!m_rootNode || !m_accDirty) + return; + +// [ m_rootNode ] +// / / / +// #0 [ fill ] [ stroke ] [ next ] +// / / | +// #1 [ fill ] [ stroke ] [ next ] +// / / | +// #2 [ fill ] [ stroke ] [ next ] +// ... +// ... + + QQuickShapeGenericNode **nodePtr = &m_rootNode; + QQuickShapeGenericNode *prevNode = nullptr; + + for (ShapePathData &d : m_sp) { + if (!*nodePtr) { + Q_ASSERT(prevNode); + *nodePtr = new QQuickShapeGenericNode; + prevNode->m_next = *nodePtr; + prevNode->appendChildNode(*nodePtr); + } + + QQuickShapeGenericNode *node = *nodePtr; + + if (m_accDirty & DirtyList) + d.effectiveDirty |= DirtyFillGeom | DirtyStrokeGeom | DirtyColor | DirtyFillGradient; + + if (!d.effectiveDirty) { + prevNode = node; + nodePtr = &node->m_next; + continue; + } + + if (d.fillColor.a == 0) { + delete node->m_fillNode; + node->m_fillNode = nullptr; + } else if (!node->m_fillNode) { + node->m_fillNode = new QQuickShapeGenericStrokeFillNode(m_item->window()); + if (node->m_strokeNode) + node->removeChildNode(node->m_strokeNode); + node->appendChildNode(node->m_fillNode); + if (node->m_strokeNode) + node->appendChildNode(node->m_strokeNode); + d.effectiveDirty |= DirtyFillGeom; + } + + if (d.strokeWidth < 0.0f || d.strokeColor.a == 0) { + delete node->m_strokeNode; + node->m_strokeNode = nullptr; + } else if (!node->m_strokeNode) { + node->m_strokeNode = new QQuickShapeGenericStrokeFillNode(m_item->window()); + node->appendChildNode(node->m_strokeNode); + d.effectiveDirty |= DirtyStrokeGeom; + } + + updateFillNode(&d, node); + updateStrokeNode(&d, node); + + d.effectiveDirty = 0; + + prevNode = node; + nodePtr = &node->m_next; + } + + if (*nodePtr && prevNode) { + prevNode->removeChildNode(*nodePtr); + delete *nodePtr; + *nodePtr = nullptr; + } + + m_accDirty = 0; +} + +void QQuickShapeGenericRenderer::updateShadowDataInNode(ShapePathData *d, QQuickShapeGenericStrokeFillNode *n) +{ + if (d->fillGradientActive) { + if (d->effectiveDirty & DirtyFillGradient) + n->m_fillGradient = d->fillGradient; + } +} + +void QQuickShapeGenericRenderer::updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node) +{ + if (!node->m_fillNode) + return; + if (!(d->effectiveDirty & (DirtyFillGeom | DirtyColor | DirtyFillGradient))) + return; + + // Make a copy of the data that will be accessed by the material on + // the render thread. This must be done even when we bail out below. + QQuickShapeGenericStrokeFillNode *n = node->m_fillNode; + updateShadowDataInNode(d, n); + + QSGGeometry *g = n->geometry(); + if (d->fillVertices.isEmpty()) { + if (g->vertexCount() || g->indexCount()) { + g->allocate(0, 0); + n->markDirty(QSGNode::DirtyGeometry); + } + return; + } + + if (d->fillGradientActive) { + QQuickShapeGenericStrokeFillNode::Material gradMat; + switch (d->fillGradientActive) { + case LinearGradient: + gradMat = QQuickShapeGenericStrokeFillNode::MatLinearGradient; + break; + case RadialGradient: + gradMat = QQuickShapeGenericStrokeFillNode::MatRadialGradient; + break; + case ConicalGradient: + gradMat = QQuickShapeGenericStrokeFillNode::MatConicalGradient; + break; + default: + Q_UNREACHABLE(); + return; + } + n->activateMaterial(m_item->window(), gradMat); + if (d->effectiveDirty & DirtyFillGradient) { + // 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 (!(d->effectiveDirty & DirtyFillGeom)) + return; + } + } else { + n->activateMaterial(m_item->window(), QQuickShapeGenericStrokeFillNode::MatSolidColor); + // fast path for updating only color values when no change in vertex positions + if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyFillGeom)) { + ColoredVertex *vdst = reinterpret_cast(g->vertexData()); + for (int i = 0; i < g->vertexCount(); ++i) + vdst[i].set(vdst[i].x, vdst[i].y, d->fillColor); + n->markDirty(QSGNode::DirtyGeometry); + return; + } + } + + const int indexCount = d->indexType == QSGGeometry::UnsignedShortType + ? d->fillIndices.count() * 2 : d->fillIndices.count(); + if (g->indexType() != d->indexType) { + g = new QSGGeometry(QSGGeometry::defaultAttributes_ColoredPoint2D(), + d->fillVertices.count(), indexCount, d->indexType); + n->setGeometry(g); + } else { + g->allocate(d->fillVertices.count(), indexCount); + } + g->setDrawingMode(QSGGeometry::DrawTriangles); + memcpy(g->vertexData(), d->fillVertices.constData(), g->vertexCount() * g->sizeOfVertex()); + memcpy(g->indexData(), d->fillIndices.constData(), g->indexCount() * g->sizeOfIndex()); + + n->markDirty(QSGNode::DirtyGeometry); +} + +void QQuickShapeGenericRenderer::updateStrokeNode(ShapePathData *d, QQuickShapeGenericNode *node) +{ + if (!node->m_strokeNode) + return; + if (!(d->effectiveDirty & (DirtyStrokeGeom | DirtyColor))) + return; + + QQuickShapeGenericStrokeFillNode *n = node->m_strokeNode; + QSGGeometry *g = n->geometry(); + if (d->strokeVertices.isEmpty()) { + if (g->vertexCount() || g->indexCount()) { + g->allocate(0, 0); + n->markDirty(QSGNode::DirtyGeometry); + } + return; + } + + n->markDirty(QSGNode::DirtyGeometry); + + // Async loading runs update once, bails out above, then updates again once + // ready. Set the material dirty then. This is in-line with fill where the + // first activateMaterial() achieves the same. + if (!g->vertexCount()) + n->markDirty(QSGNode::DirtyMaterial); + + if ((d->effectiveDirty & DirtyColor) && !(d->effectiveDirty & DirtyStrokeGeom)) { + ColoredVertex *vdst = reinterpret_cast(g->vertexData()); + for (int i = 0; i < g->vertexCount(); ++i) + vdst[i].set(vdst[i].x, vdst[i].y, d->strokeColor); + return; + } + + g->allocate(d->strokeVertices.count(), 0); + g->setDrawingMode(QSGGeometry::DrawTriangleStrip); + memcpy(g->vertexData(), d->strokeVertices.constData(), g->vertexCount() * g->sizeOfVertex()); +} + +QSGMaterial *QQuickShapeGenericMaterialFactory::createVertexColor(QQuickWindow *window) +{ + QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); + +#if QT_CONFIG(opengl) + if (api == QSGRendererInterface::OpenGL) + return new QSGVertexColorMaterial; +#endif + + qWarning("Vertex-color material: Unsupported graphics API %d", api); + return nullptr; +} + +QSGMaterial *QQuickShapeGenericMaterialFactory::createLinearGradient(QQuickWindow *window, + QQuickShapeGenericStrokeFillNode *node) +{ + QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); + +#if QT_CONFIG(opengl) + if (api == QSGRendererInterface::OpenGL) + return new QQuickShapeLinearGradientMaterial(node); +#else + Q_UNUSED(node); +#endif + + qWarning("Linear gradient material: Unsupported graphics API %d", api); + return nullptr; +} + +QSGMaterial *QQuickShapeGenericMaterialFactory::createRadialGradient(QQuickWindow *window, + QQuickShapeGenericStrokeFillNode *node) +{ + QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); + +#if QT_CONFIG(opengl) + if (api == QSGRendererInterface::OpenGL) + return new QQuickShapeRadialGradientMaterial(node); +#else + Q_UNUSED(node); +#endif + + qWarning("Radial gradient material: Unsupported graphics API %d", api); + return nullptr; +} + +QSGMaterial *QQuickShapeGenericMaterialFactory::createConicalGradient(QQuickWindow *window, + QQuickShapeGenericStrokeFillNode *node) +{ + QSGRendererInterface::GraphicsApi api = window->rendererInterface()->graphicsApi(); + +#if QT_CONFIG(opengl) + if (api == QSGRendererInterface::OpenGL) + return new QQuickShapeConicalGradientMaterial(node); +#else + Q_UNUSED(node); +#endif + + qWarning("Conical gradient material: Unsupported graphics API %d", api); + return nullptr; +} + +#if QT_CONFIG(opengl) + +QSGMaterialType QQuickShapeLinearGradientShader::type; + +QQuickShapeLinearGradientShader::QQuickShapeLinearGradientShader() +{ + setShaderSourceFile(QOpenGLShader::Vertex, + QStringLiteral(":/qt-project.org/shapes/shaders/lineargradient.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, + QStringLiteral(":/qt-project.org/shapes/shaders/lineargradient.frag")); +} + +void QQuickShapeLinearGradientShader::initialize() +{ + m_opacityLoc = program()->uniformLocation("opacity"); + m_matrixLoc = program()->uniformLocation("matrix"); + m_gradStartLoc = program()->uniformLocation("gradStart"); + m_gradEndLoc = program()->uniformLocation("gradEnd"); +} + +void QQuickShapeLinearGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *) +{ + QQuickShapeLinearGradientMaterial *m = static_cast(mat); + + if (state.isOpacityDirty()) + program()->setUniformValue(m_opacityLoc, state.opacity()); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrixLoc, state.combinedMatrix()); + + QQuickShapeGenericStrokeFillNode *node = m->node(); + program()->setUniformValue(m_gradStartLoc, QVector2D(node->m_fillGradient.a)); + program()->setUniformValue(m_gradEndLoc, QVector2D(node->m_fillGradient.b)); + + const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); + QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); + tx->bind(); +} + +char const *const *QQuickShapeLinearGradientShader::attributeNames() const +{ + static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr }; + return attr; +} + +int QQuickShapeLinearGradientMaterial::compare(const QSGMaterial *other) const +{ + Q_ASSERT(other && type() == other->type()); + const QQuickShapeLinearGradientMaterial *m = static_cast(other); + + QQuickShapeGenericStrokeFillNode *a = node(); + QQuickShapeGenericStrokeFillNode *b = m->node(); + Q_ASSERT(a && b); + if (a == b) + return 0; + + const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient; + const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient; + + if (int d = ga->spread - gb->spread) + return d; + + if (int d = ga->a.x() - gb->a.x()) + return d; + if (int d = ga->a.y() - gb->a.y()) + return d; + if (int d = ga->b.x() - gb->b.x()) + return d; + if (int d = ga->b.y() - gb->b.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; +} + +QSGMaterialType QQuickShapeRadialGradientShader::type; + +QQuickShapeRadialGradientShader::QQuickShapeRadialGradientShader() +{ + setShaderSourceFile(QOpenGLShader::Vertex, + QStringLiteral(":/qt-project.org/shapes/shaders/radialgradient.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, + QStringLiteral(":/qt-project.org/shapes/shaders/radialgradient.frag")); +} + +void QQuickShapeRadialGradientShader::initialize() +{ + QOpenGLShaderProgram *prog = program(); + m_opacityLoc = prog->uniformLocation("opacity"); + m_matrixLoc = prog->uniformLocation("matrix"); + m_translationPointLoc = prog->uniformLocation("translationPoint"); + m_focalToCenterLoc = prog->uniformLocation("focalToCenter"); + m_centerRadiusLoc = prog->uniformLocation("centerRadius"); + m_focalRadiusLoc = prog->uniformLocation("focalRadius"); +} + +void QQuickShapeRadialGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *) +{ + QQuickShapeRadialGradientMaterial *m = static_cast(mat); + + if (state.isOpacityDirty()) + program()->setUniformValue(m_opacityLoc, state.opacity()); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrixLoc, state.combinedMatrix()); + + QQuickShapeGenericStrokeFillNode *node = m->node(); + + const QPointF centerPoint = node->m_fillGradient.a; + const QPointF focalPoint = node->m_fillGradient.b; + const QPointF focalToCenter = centerPoint - focalPoint; + const GLfloat centerRadius = node->m_fillGradient.v0; + const GLfloat focalRadius = node->m_fillGradient.v1; + + program()->setUniformValue(m_translationPointLoc, focalPoint); + program()->setUniformValue(m_centerRadiusLoc, centerRadius); + program()->setUniformValue(m_focalRadiusLoc, focalRadius); + program()->setUniformValue(m_focalToCenterLoc, focalToCenter); + + const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, node->m_fillGradient.spread); + QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); + tx->bind(); +} + +char const *const *QQuickShapeRadialGradientShader::attributeNames() const +{ + static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr }; + return attr; +} + +int QQuickShapeRadialGradientMaterial::compare(const QSGMaterial *other) const +{ + Q_ASSERT(other && type() == other->type()); + const QQuickShapeRadialGradientMaterial *m = static_cast(other); + + QQuickShapeGenericStrokeFillNode *a = node(); + QQuickShapeGenericStrokeFillNode *b = m->node(); + Q_ASSERT(a && b); + if (a == b) + return 0; + + const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient; + const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient; + + if (int d = ga->spread - gb->spread) + return d; + + if (int d = ga->a.x() - gb->a.x()) + return d; + if (int d = ga->a.y() - gb->a.y()) + return d; + if (int d = ga->b.x() - gb->b.x()) + return d; + if (int d = ga->b.y() - gb->b.y()) + return d; + + if (int d = ga->v0 - gb->v0) + return d; + if (int d = ga->v1 - gb->v1) + 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; +} + +QSGMaterialType QQuickShapeConicalGradientShader::type; + +QQuickShapeConicalGradientShader::QQuickShapeConicalGradientShader() +{ + setShaderSourceFile(QOpenGLShader::Vertex, + QStringLiteral(":/qt-project.org/shapes/shaders/conicalgradient.vert")); + setShaderSourceFile(QOpenGLShader::Fragment, + QStringLiteral(":/qt-project.org/shapes/shaders/conicalgradient.frag")); +} + +void QQuickShapeConicalGradientShader::initialize() +{ + QOpenGLShaderProgram *prog = program(); + m_opacityLoc = prog->uniformLocation("opacity"); + m_matrixLoc = prog->uniformLocation("matrix"); + m_angleLoc = prog->uniformLocation("angle"); + m_translationPointLoc = prog->uniformLocation("translationPoint"); +} + +void QQuickShapeConicalGradientShader::updateState(const RenderState &state, QSGMaterial *mat, QSGMaterial *) +{ + QQuickShapeConicalGradientMaterial *m = static_cast(mat); + + if (state.isOpacityDirty()) + program()->setUniformValue(m_opacityLoc, state.opacity()); + + if (state.isMatrixDirty()) + program()->setUniformValue(m_matrixLoc, state.combinedMatrix()); + + QQuickShapeGenericStrokeFillNode *node = m->node(); + + const QPointF centerPoint = node->m_fillGradient.a; + const GLfloat angle = -qDegreesToRadians(node->m_fillGradient.v0); + + program()->setUniformValue(m_angleLoc, angle); + program()->setUniformValue(m_translationPointLoc, centerPoint); + + const QQuickShapeGradientCache::Key cacheKey(node->m_fillGradient.stops, QQuickShapeGradient::RepeatSpread); + QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); + tx->bind(); +} + +char const *const *QQuickShapeConicalGradientShader::attributeNames() const +{ + static const char *const attr[] = { "vertexCoord", "vertexColor", nullptr }; + return attr; +} + +int QQuickShapeConicalGradientMaterial::compare(const QSGMaterial *other) const +{ + Q_ASSERT(other && type() == other->type()); + const QQuickShapeConicalGradientMaterial *m = static_cast(other); + + QQuickShapeGenericStrokeFillNode *a = node(); + QQuickShapeGenericStrokeFillNode *b = m->node(); + Q_ASSERT(a && b); + if (a == b) + return 0; + + const QQuickAbstractPathRenderer::GradientDesc *ga = &a->m_fillGradient; + const QQuickAbstractPathRenderer::GradientDesc *gb = &b->m_fillGradient; + + if (int d = ga->a.x() - gb->a.x()) + return d; + if (int d = ga->a.y() - gb->a.y()) + return d; + + if (int d = ga->v0 - gb->v0) + 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_CONFIG(opengl) + +QT_END_NAMESPACE diff --git a/src/quickshapes/qquickshapegenericrenderer_p.h b/src/quickshapes/qquickshapegenericrenderer_p.h new file mode 100644 index 0000000000..9928d7ab72 --- /dev/null +++ b/src/quickshapes/qquickshapegenericrenderer_p.h @@ -0,0 +1,393 @@ +/**************************************************************************** +** +** 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 QQUICKSHAPEGENERICRENDERER_P_H +#define QQUICKSHAPEGENERICRENDERER_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 +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickShapeGenericNode; +class QQuickShapeGenericStrokeFillNode; +class QQuickShapeFillRunnable; +class QQuickShapeStrokeRunnable; + +class QQuickShapeGenericRenderer : public QQuickAbstractPathRenderer +{ +public: + enum Dirty { + DirtyFillGeom = 0x01, + DirtyStrokeGeom = 0x02, + DirtyColor = 0x04, + DirtyFillGradient = 0x08, + DirtyList = 0x10 // only for accDirty + }; + + QQuickShapeGenericRenderer(QQuickItem *item) + : m_item(item), + m_api(QSGRendererInterface::Unknown), + m_rootNode(nullptr), + m_accDirty(0), + m_asyncCallback(nullptr), + m_asyncCallbackData(nullptr) + { } + ~QQuickShapeGenericRenderer(); + + void beginSync(int totalCount) override; + void setPath(int index, const QQuickPath *path) override; + void setStrokeColor(int index, const QColor &color) override; + void setStrokeWidth(int index, qreal w) override; + void setFillColor(int index, const QColor &color) override; + void setFillRule(int index, QQuickShapePath::FillRule fillRule) override; + void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override; + void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override; + void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, + qreal dashOffset, const QVector &dashPattern) override; + void setFillGradient(int index, QQuickShapeGradient *gradient) override; + void endSync(bool async) override; + void setAsyncCallback(void (*)(void *), void *) override; + Flags flags() const override { return SupportsAsync; } + + void updateNode() override; + + void setRootNode(QQuickShapeGenericNode *node); + + struct Color4ub { unsigned char r, g, b, a; }; + typedef QVector VertexContainerType; + typedef QVector IndexContainerType; + + static void triangulateFill(const QPainterPath &path, + const Color4ub &fillColor, + VertexContainerType *fillVertices, + IndexContainerType *fillIndices, + QSGGeometry::Type *indexType, + bool supportsElementIndexUint); + static void triangulateStroke(const QPainterPath &path, + const QPen &pen, + const Color4ub &strokeColor, + VertexContainerType *strokeVertices, + const QSize &clipSize); + +private: + void maybeUpdateAsyncItem(); + + struct ShapePathData { + float strokeWidth; + QPen pen; + Color4ub strokeColor; + Color4ub fillColor; + Qt::FillRule fillRule; + QPainterPath path; + FillGradientType fillGradientActive; + GradientDesc fillGradient; + VertexContainerType fillVertices; + IndexContainerType fillIndices; + QSGGeometry::Type indexType; + VertexContainerType strokeVertices; + int syncDirty; + int effectiveDirty = 0; + QQuickShapeFillRunnable *pendingFill = nullptr; + QQuickShapeStrokeRunnable *pendingStroke = nullptr; + }; + + void updateShadowDataInNode(ShapePathData *d, QQuickShapeGenericStrokeFillNode *n); + void updateFillNode(ShapePathData *d, QQuickShapeGenericNode *node); + void updateStrokeNode(ShapePathData *d, QQuickShapeGenericNode *node); + + QQuickItem *m_item; + QSGRendererInterface::GraphicsApi m_api; + QQuickShapeGenericNode *m_rootNode; + QVector m_sp; + int m_accDirty; + void (*m_asyncCallback)(void *); + void *m_asyncCallbackData; +}; + +class QQuickShapeFillRunnable : public QObject, public QRunnable +{ + Q_OBJECT + +public: + void run() override; + + bool orphaned = false; + + // input + QPainterPath path; + QQuickShapeGenericRenderer::Color4ub fillColor; + bool supportsElementIndexUint; + + // output + QQuickShapeGenericRenderer::VertexContainerType fillVertices; + QQuickShapeGenericRenderer::IndexContainerType fillIndices; + QSGGeometry::Type indexType; + +Q_SIGNALS: + void done(QQuickShapeFillRunnable *self); +}; + +class QQuickShapeStrokeRunnable : public QObject, public QRunnable +{ + Q_OBJECT + +public: + void run() override; + + bool orphaned = false; + + // input + QPainterPath path; + QPen pen; + QQuickShapeGenericRenderer::Color4ub strokeColor; + QSize clipSize; + + // output + QQuickShapeGenericRenderer::VertexContainerType strokeVertices; + +Q_SIGNALS: + void done(QQuickShapeStrokeRunnable *self); +}; + +class QQuickShapeGenericStrokeFillNode : public QSGGeometryNode +{ +public: + QQuickShapeGenericStrokeFillNode(QQuickWindow *window); + + enum Material { + MatSolidColor, + MatLinearGradient, + MatRadialGradient, + MatConicalGradient + }; + + void activateMaterial(QQuickWindow *window, Material m); + + // shadow data for custom materials + QQuickAbstractPathRenderer::GradientDesc m_fillGradient; + +private: + QScopedPointer m_material; + + friend class QQuickShapeGenericRenderer; +}; + +class QQuickShapeGenericNode : public QSGNode +{ +public: + QQuickShapeGenericStrokeFillNode *m_fillNode = nullptr; + QQuickShapeGenericStrokeFillNode *m_strokeNode = nullptr; + QQuickShapeGenericNode *m_next = nullptr; +}; + +class QQuickShapeGenericMaterialFactory +{ +public: + static QSGMaterial *createVertexColor(QQuickWindow *window); + static QSGMaterial *createLinearGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); + static QSGMaterial *createRadialGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); + static QSGMaterial *createConicalGradient(QQuickWindow *window, QQuickShapeGenericStrokeFillNode *node); +}; + +#if QT_CONFIG(opengl) + +class QQuickShapeLinearGradientShader : public QSGMaterialShader +{ +public: + QQuickShapeLinearGradientShader(); + + 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 = -1; + int m_matrixLoc = -1; + int m_gradStartLoc = -1; + int m_gradEndLoc = -1; +}; + +class QQuickShapeLinearGradientMaterial : public QSGMaterial +{ +public: + QQuickShapeLinearGradientMaterial(QQuickShapeGenericStrokeFillNode *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 Shape-space coordinate and so no modifications + // are welcome. + setFlag(Blending | RequiresFullMatrix); + } + + QSGMaterialType *type() const override + { + return &QQuickShapeLinearGradientShader::type; + } + + int compare(const QSGMaterial *other) const override; + + QSGMaterialShader *createShader() const override + { + return new QQuickShapeLinearGradientShader; + } + + QQuickShapeGenericStrokeFillNode *node() const { return m_node; } + +private: + QQuickShapeGenericStrokeFillNode *m_node; +}; + +class QQuickShapeRadialGradientShader : public QSGMaterialShader +{ +public: + QQuickShapeRadialGradientShader(); + + 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 = -1; + int m_matrixLoc = -1; + int m_translationPointLoc = -1; + int m_focalToCenterLoc = -1; + int m_centerRadiusLoc = -1; + int m_focalRadiusLoc = -1; +}; + +class QQuickShapeRadialGradientMaterial : public QSGMaterial +{ +public: + QQuickShapeRadialGradientMaterial(QQuickShapeGenericStrokeFillNode *node) + : m_node(node) + { + setFlag(Blending | RequiresFullMatrix); + } + + QSGMaterialType *type() const override + { + return &QQuickShapeRadialGradientShader::type; + } + + int compare(const QSGMaterial *other) const override; + + QSGMaterialShader *createShader() const override + { + return new QQuickShapeRadialGradientShader; + } + + QQuickShapeGenericStrokeFillNode *node() const { return m_node; } + +private: + QQuickShapeGenericStrokeFillNode *m_node; +}; + +class QQuickShapeConicalGradientShader : public QSGMaterialShader +{ +public: + QQuickShapeConicalGradientShader(); + + 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 = -1; + int m_matrixLoc = -1; + int m_angleLoc = -1; + int m_translationPointLoc = -1; +}; + +class QQuickShapeConicalGradientMaterial : public QSGMaterial +{ +public: + QQuickShapeConicalGradientMaterial(QQuickShapeGenericStrokeFillNode *node) + : m_node(node) + { + setFlag(Blending | RequiresFullMatrix); + } + + QSGMaterialType *type() const override + { + return &QQuickShapeConicalGradientShader::type; + } + + int compare(const QSGMaterial *other) const override; + + QSGMaterialShader *createShader() const override + { + return new QQuickShapeConicalGradientShader; + } + + QQuickShapeGenericStrokeFillNode *node() const { return m_node; } + +private: + QQuickShapeGenericStrokeFillNode *m_node; +}; + +#endif // QT_CONFIG(opengl) + +QT_END_NAMESPACE + +#endif // QQUICKSHAPEGENERICRENDERER_P_H diff --git a/src/quickshapes/qquickshapenvprrenderer.cpp b/src/quickshapes/qquickshapenvprrenderer.cpp new file mode 100644 index 0000000000..51af0d8961 --- /dev/null +++ b/src/quickshapes/qquickshapenvprrenderer.cpp @@ -0,0 +1,1001 @@ +/**************************************************************************** +** +** 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 "qquickshapenvprrenderer_p.h" +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +void QQuickShapeNvprRenderer::beginSync(int totalCount) +{ + if (m_sp.count() != totalCount) { + m_sp.resize(totalCount); + m_accDirty |= DirtyList; + } +} + +void QQuickShapeNvprRenderer::setPath(int index, const QQuickPath *path) +{ + ShapePathGuiData &d(m_sp[index]); + convertPath(path, &d); + d.dirty |= DirtyPath; + m_accDirty |= DirtyPath; +} + +void QQuickShapeNvprRenderer::setStrokeColor(int index, const QColor &color) +{ + ShapePathGuiData &d(m_sp[index]); + d.strokeColor = color; + d.dirty |= DirtyStyle; + m_accDirty |= DirtyStyle; +} + +void QQuickShapeNvprRenderer::setStrokeWidth(int index, qreal w) +{ + ShapePathGuiData &d(m_sp[index]); + d.strokeWidth = w; + d.dirty |= DirtyStyle; + m_accDirty |= DirtyStyle; +} + +void QQuickShapeNvprRenderer::setFillColor(int index, const QColor &color) +{ + ShapePathGuiData &d(m_sp[index]); + d.fillColor = color; + d.dirty |= DirtyStyle; + m_accDirty |= DirtyStyle; +} + +void QQuickShapeNvprRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule) +{ + ShapePathGuiData &d(m_sp[index]); + d.fillRule = fillRule; + d.dirty |= DirtyFillRule; + m_accDirty |= DirtyFillRule; +} + +void QQuickShapeNvprRenderer::setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) +{ + ShapePathGuiData &d(m_sp[index]); + d.joinStyle = joinStyle; + d.miterLimit = miterLimit; + d.dirty |= DirtyStyle; + m_accDirty |= DirtyStyle; +} + +void QQuickShapeNvprRenderer::setCapStyle(int index, QQuickShapePath::CapStyle capStyle) +{ + ShapePathGuiData &d(m_sp[index]); + d.capStyle = capStyle; + d.dirty |= DirtyStyle; + m_accDirty |= DirtyStyle; +} + +void QQuickShapeNvprRenderer::setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, + qreal dashOffset, const QVector &dashPattern) +{ + ShapePathGuiData &d(m_sp[index]); + d.dashActive = strokeStyle == QQuickShapePath::DashLine; + d.dashOffset = dashOffset; + d.dashPattern = dashPattern; + d.dirty |= DirtyDash; + m_accDirty |= DirtyDash; +} + +void QQuickShapeNvprRenderer::setFillGradient(int index, QQuickShapeGradient *gradient) +{ + ShapePathGuiData &d(m_sp[index]); + if (gradient) { + d.fillGradient.stops = gradient->gradientStops(); // sorted + d.fillGradient.spread = gradient->spread(); + if (QQuickShapeLinearGradient *g = qobject_cast(gradient)) { + d.fillGradientActive = LinearGradient; + d.fillGradient.a = QPointF(g->x1(), g->y1()); + d.fillGradient.b = QPointF(g->x2(), g->y2()); + } else if (QQuickShapeRadialGradient *g = qobject_cast(gradient)) { + d.fillGradientActive = RadialGradient; + d.fillGradient.a = QPointF(g->centerX(), g->centerY()); + d.fillGradient.b = QPointF(g->focalX(), g->focalY()); + d.fillGradient.v0 = g->centerRadius(); + d.fillGradient.v1 = g->focalRadius(); + } else if (QQuickShapeConicalGradient *g = qobject_cast(gradient)) { + d.fillGradientActive = ConicalGradient; + d.fillGradient.a = QPointF(g->centerX(), g->centerY()); + d.fillGradient.v0 = g->angle(); + } else { + Q_UNREACHABLE(); + } + } else { + d.fillGradientActive = NoGradient; + } + d.dirty |= DirtyFillGradient; + m_accDirty |= DirtyFillGradient; +} + +void QQuickShapeNvprRenderer::endSync(bool) +{ +} + +void QQuickShapeNvprRenderer::setNode(QQuickShapeNvprRenderNode *node) +{ + if (m_node != node) { + m_node = node; + m_accDirty |= DirtyList; + } +} + +QDebug operator<<(QDebug debug, const QQuickShapeNvprRenderer::NvprPath &path) +{ + QDebugStateSaver saver(debug); + debug.space().noquote(); + if (!path.str.isEmpty()) { + debug << "Path with SVG string" << path.str; + return debug; + } + 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 *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 *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 *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 *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 QQuickShapeNvprRenderer::convertPath(const QQuickPath *path, ShapePathGuiData *d) +{ + d->path = NvprPath(); + if (!path) + return; + + const QList &pp(QQuickPathPrivate::get(path)->_pathElements); + if (pp.isEmpty()) + return; + + QPointF startPos(path->startX(), path->startY()); + QPointF pos(startPos); + if (!qFuzzyIsNull(pos.x()) || !qFuzzyIsNull(pos.y())) { + d->path.cmd.append(GL_MOVE_TO_NV); + d->path.coord.append(pos.x()); + d->path.coord.append(pos.y()); + } + + for (QQuickPathElement *e : pp) { + if (QQuickPathMove *o = qobject_cast(e)) { + d->path.cmd.append(GL_MOVE_TO_NV); + appendCoords(&d->path.coord, o, &pos); + startPos = pos; + } else if (QQuickPathLine *o = qobject_cast(e)) { + d->path.cmd.append(GL_LINE_TO_NV); + appendCoords(&d->path.coord, o, &pos); + } else if (QQuickPathQuad *o = qobject_cast(e)) { + d->path.cmd.append(GL_QUADRATIC_CURVE_TO_NV); + appendControlCoords(&d->path.coord, o, pos); + appendCoords(&d->path.coord, o, &pos); + } else if (QQuickPathCubic *o = qobject_cast(e)) { + d->path.cmd.append(GL_CUBIC_CURVE_TO_NV); + appendControl1Coords(&d->path.coord, o, pos); + appendControl2Coords(&d->path.coord, o, pos); + appendCoords(&d->path.coord, o, &pos); + } else if (QQuickPathArc *o = qobject_cast(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; + d->path.cmd.append(cmd); + d->path.coord.append(o->radiusX()); + d->path.coord.append(o->radiusY()); + d->path.coord.append(o->xAxisRotation()); + appendCoords(&d->path.coord, o, &pos); + } else if (QQuickPathSvg *o = qobject_cast(e)) { + // PathSvg cannot be combined with other elements. But take at + // least startX and startY into account. + if (d->path.str.isEmpty()) + d->path.str = QString(QStringLiteral("M %1 %2 ")).arg(pos.x()).arg(pos.y()).toUtf8(); + d->path.str.append(o->path().toUtf8()); + } else if (QQuickPathAngleArc *o = qobject_cast(e)) { + QRectF rect(o->centerX() - o->radiusX(), o->centerY() - o->radiusY(), o->radiusX() * 2, o->radiusY() * 2); + QPointF startPoint; + QPointF endPoint; + qt_find_ellipse_coords(rect, o->startAngle(), -o->sweepAngle(), &startPoint, &endPoint); + + // get to our starting position + if (o->moveToStart()) + d->path.cmd.append(GL_MOVE_TO_NV); + else + d->path.cmd.append(GL_LINE_TO_NV); // ### should we check if startPoint == pos? + d->path.coord.append(startPoint.x()); + d->path.coord.append(startPoint.y()); + + const bool sweepFlag = o->sweepAngle() > 0; // maps to CCW, not a typo + d->path.cmd.append(qAbs(o->sweepAngle()) > 180.0 + ? (sweepFlag ? GL_LARGE_CCW_ARC_TO_NV : GL_LARGE_CW_ARC_TO_NV) + : (sweepFlag ? GL_SMALL_CCW_ARC_TO_NV : GL_SMALL_CW_ARC_TO_NV)); + d->path.coord.append(o->radiusX()); + d->path.coord.append(o->radiusY()); + d->path.coord.append(0); // xAxisRotation + d->path.coord.append(endPoint.x()); + d->path.coord.append(endPoint.y()); + pos = endPoint; + } else { + qWarning() << "Shape/NVPR: unsupported Path element" << e; + } + } + + // For compatibility with QTriangulatingStroker. SVG and others would not + // implicitly close the path when end_pos == start_pos (start_pos being the + // last moveTo pos); that would still need an explicit 'z' or similar. We + // don't have an explicit close command, so just fake a close when the + // positions match. + if (pos == startPos) + d->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 QQuickShapeNvprRenderer::updateNode() +{ + // Called on the render thread with gui blocked -> update the node with its + // own copy of all relevant data. + + if (!m_accDirty) + return; + + const int count = m_sp.count(); + const bool listChanged = m_accDirty & DirtyList; + if (listChanged) + m_node->m_sp.resize(count); + + for (int i = 0; i < count; ++i) { + ShapePathGuiData &src(m_sp[i]); + QQuickShapeNvprRenderNode::ShapePathRenderData &dst(m_node->m_sp[i]); + + int dirty = src.dirty; + src.dirty = 0; + if (listChanged) + dirty |= DirtyPath | DirtyStyle | DirtyFillRule | DirtyDash | DirtyFillGradient; + + // updateNode() can be called several times with different dirty + // states before render() gets invoked. So accumulate. + dst.dirty |= dirty; + + if (dirty & DirtyPath) + dst.source = src.path; + + if (dirty & DirtyStyle) { + dst.strokeWidth = src.strokeWidth; + dst.strokeColor = qsg_premultiply(src.strokeColor, 1.0f); + dst.fillColor = qsg_premultiply(src.fillColor, 1.0f); + switch (src.joinStyle) { + case QQuickShapePath::MiterJoin: + dst.joinStyle = GL_MITER_TRUNCATE_NV; + break; + case QQuickShapePath::BevelJoin: + dst.joinStyle = GL_BEVEL_NV; + break; + case QQuickShapePath::RoundJoin: + dst.joinStyle = GL_ROUND_NV; + break; + default: + Q_UNREACHABLE(); + } + dst.miterLimit = src.miterLimit; + switch (src.capStyle) { + case QQuickShapePath::FlatCap: + dst.capStyle = GL_FLAT; + break; + case QQuickShapePath::SquareCap: + dst.capStyle = GL_SQUARE_NV; + break; + case QQuickShapePath::RoundCap: + dst.capStyle = GL_ROUND_NV; + break; + default: + Q_UNREACHABLE(); + } + } + + if (dirty & DirtyFillRule) { + switch (src.fillRule) { + case QQuickShapePath::OddEvenFill: + dst.fillRule = GL_INVERT; + break; + case QQuickShapePath::WindingFill: + dst.fillRule = GL_COUNT_UP_NV; + break; + default: + Q_UNREACHABLE(); + } + } + + if (dirty & DirtyDash) { + // Multiply by strokeWidth because the Shape API follows QPen + // meaning the input dash pattern and dash offset here are in width units. + dst.dashOffset = src.dashOffset * src.strokeWidth; + if (src.dashActive) { + if (src.dashPattern.isEmpty()) { + // default values for DashLine as defined in qpen.cpp + dst.dashPattern.resize(2); + dst.dashPattern[0] = 4 * src.strokeWidth; // dash + dst.dashPattern[1] = 2 * src.strokeWidth; // space + } else { + dst.dashPattern.resize(src.dashPattern.count()); + for (int i = 0; i < src.dashPattern.count(); ++i) + dst.dashPattern[i] = GLfloat(src.dashPattern[i]) * src.strokeWidth; + + // QPen expects a dash pattern of even length and so should we + if (src.dashPattern.count() % 2 != 0) { + qWarning("QQuickShapeNvprRenderNode: dash pattern not of even length"); + dst.dashPattern << src.strokeWidth; + } + } + } else { + dst.dashPattern.clear(); + } + } + + if (dirty & DirtyFillGradient) { + dst.fillGradientActive = src.fillGradientActive; + if (src.fillGradientActive) + dst.fillGradient = src.fillGradient; + } + } + + m_node->markDirty(QSGNode::DirtyMaterial); + m_accDirty = 0; +} + +bool QQuickShapeNvprRenderNode::nvprInited = false; +QQuickNvprFunctions QQuickShapeNvprRenderNode::nvpr; +QQuickNvprMaterialManager QQuickShapeNvprRenderNode::mtlmgr; + +QQuickShapeNvprRenderNode::~QQuickShapeNvprRenderNode() +{ + releaseResources(); +} + +void QQuickShapeNvprRenderNode::releaseResources() +{ + for (ShapePathRenderData &d : m_sp) { + if (d.path) { + nvpr.deletePaths(d.path, 1); + d.path = 0; + } + if (d.fallbackFbo) { + delete d.fallbackFbo; + d.fallbackFbo = nullptr; + } + } + + m_fallbackBlitter.destroy(); +} + +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 if (m == MatRadialGradient) { + static const char *fragSrc = + "#version 310 es\n" + "precision highp float;\n" + "uniform sampler2D gradTab;\n" + "uniform float opacity;\n" + "uniform vec2 focalToCenter;\n" + "uniform float centerRadius;\n" + "uniform float focalRadius;\n" + "uniform vec2 translationPoint;\n" + "layout(location = 0) in vec2 uv;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " vec2 coord = uv - translationPoint;\n" + " float rd = centerRadius - focalRadius;\n" + " float b = 2.0 * (rd * focalRadius + dot(coord, focalToCenter));\n" + " float fmp2_m_radius2 = -focalToCenter.x * focalToCenter.x - focalToCenter.y * focalToCenter.y + rd * rd;\n" + " float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2);\n" + " float det = b * b - 4.0 * fmp2_m_radius2 * ((focalRadius * focalRadius) - dot(coord, coord));\n" + " vec4 result = vec4(0.0);\n" + " if (det >= 0.0) {\n" + " float detSqrt = sqrt(det);\n" + " float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2);\n" + " if (focalRadius + w * (centerRadius - focalRadius) >= 0.0)\n" + " result = texture(gradTab, vec2(w, 0.5)) * opacity;\n" + " }\n" + " fragColor = result;\n" + "}\n"; + if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) { + qWarning("NVPR: Failed to create shader pipeline for radial 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, "focalToCenter"); + Q_ASSERT(mtl.uniLoc[2] >= 0); + mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "centerRadius"); + Q_ASSERT(mtl.uniLoc[3] >= 0); + mtl.uniLoc[4] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "focalRadius"); + Q_ASSERT(mtl.uniLoc[4] >= 0); + mtl.uniLoc[5] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "translationPoint"); + Q_ASSERT(mtl.uniLoc[5] >= 0); + } else if (m == MatConicalGradient) { + static const char *fragSrc = + "#version 310 es\n" + "precision highp float;\n" + "#define INVERSE_2PI 0.1591549430918953358\n" + "uniform sampler2D gradTab;\n" + "uniform float opacity;\n" + "uniform float angle;\n" + "uniform vec2 translationPoint;\n" + "layout(location = 0) in vec2 uv;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " vec2 coord = uv - translationPoint;\n" + " float t;\n" + " if (abs(coord.y) == abs(coord.x))\n" + " t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI;\n" + " else\n" + " t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI;\n" + " fragColor = texture(gradTab, vec2(t - floor(t), 0.5)) * opacity;\n" + "}\n"; + if (!m_nvpr->createFragmentOnlyPipeline(fragSrc, &mtl.ppl, &mtl.prg)) { + qWarning("NVPR: Failed to create shader pipeline for conical 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, "angle"); + Q_ASSERT(mtl.uniLoc[2] >= 0); + mtl.uniLoc[3] = f->glGetProgramResourceLocation(mtl.prg, GL_UNIFORM, "translationPoint"); + Q_ASSERT(mtl.uniLoc[3] >= 0); + } else { + Q_UNREACHABLE(); + } + } + + f->glBindProgramPipeline(mtl.ppl); + + return &mtl; +} + +void QQuickShapeNvprRenderNode::updatePath(ShapePathRenderData *d) +{ + if (d->dirty & QQuickShapeNvprRenderer::DirtyPath) { + if (!d->path) { + d->path = nvpr.genPaths(1); + Q_ASSERT(d->path != 0); + } + if (d->source.str.isEmpty()) { + nvpr.pathCommands(d->path, d->source.cmd.count(), d->source.cmd.constData(), + d->source.coord.count(), GL_FLOAT, d->source.coord.constData()); + } else { + nvpr.pathString(d->path, GL_PATH_FORMAT_SVG_NV, d->source.str.count(), d->source.str.constData()); + } + } + + if (d->dirty & QQuickShapeNvprRenderer::DirtyStyle) { + nvpr.pathParameterf(d->path, GL_PATH_STROKE_WIDTH_NV, d->strokeWidth); + nvpr.pathParameteri(d->path, GL_PATH_JOIN_STYLE_NV, d->joinStyle); + nvpr.pathParameteri(d->path, GL_PATH_MITER_LIMIT_NV, d->miterLimit); + nvpr.pathParameteri(d->path, GL_PATH_END_CAPS_NV, d->capStyle); + nvpr.pathParameteri(d->path, GL_PATH_DASH_CAPS_NV, d->capStyle); + } + + if (d->dirty & QQuickShapeNvprRenderer::DirtyDash) { + nvpr.pathParameterf(d->path, GL_PATH_DASH_OFFSET_NV, d->dashOffset); + // count == 0 -> no dash + nvpr.pathDashArray(d->path, d->dashPattern.count(), d->dashPattern.constData()); + } + + if (d->dirty) + d->fallbackValid = false; +} + +void QQuickShapeNvprRenderNode::renderStroke(ShapePathRenderData *d, int strokeStencilValue, int writeMask) +{ + QQuickNvprMaterialManager::MaterialDesc *mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid); + f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0], + d->strokeColor.x(), d->strokeColor.y(), d->strokeColor.z(), d->strokeColor.w()); + f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity()); + + nvpr.stencilThenCoverStrokePath(d->path, strokeStencilValue, writeMask, GL_CONVEX_HULL_NV); +} + +void QQuickShapeNvprRenderNode::renderFill(ShapePathRenderData *d) +{ + QQuickNvprMaterialManager::MaterialDesc *mtl = nullptr; + if (d->fillGradientActive) { + QQuickShapeGradient::SpreadMode spread = d->fillGradient.spread; + if (d->fillGradientActive == QQuickAbstractPathRenderer::LinearGradient) { + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatLinearGradient); + // 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], d->fillGradient.a.x(), d->fillGradient.a.y()); + f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], d->fillGradient.b.x(), d->fillGradient.b.y()); + } else if (d->fillGradientActive == QQuickAbstractPathRenderer::RadialGradient) { + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatRadialGradient); + // simply drive uv (location 0) with x and y, just like for the linear gradient + GLfloat coeff[6] = { 1, 0, 0, + 0, 1, 0 }; + nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff); + + const QPointF centerPoint = d->fillGradient.a; + const QPointF focalPoint = d->fillGradient.b; + const QPointF focalToCenter = centerPoint - focalPoint; + const GLfloat centerRadius = d->fillGradient.v0; + const GLfloat focalRadius = d->fillGradient.v1; + + f->glProgramUniform2f(mtl->prg, mtl->uniLoc[2], focalToCenter.x(), focalToCenter.y()); + f->glProgramUniform1f(mtl->prg, mtl->uniLoc[3], centerRadius); + f->glProgramUniform1f(mtl->prg, mtl->uniLoc[4], focalRadius); + f->glProgramUniform2f(mtl->prg, mtl->uniLoc[5], focalPoint.x(), focalPoint.y()); + } else if (d->fillGradientActive == QQuickAbstractPathRenderer::ConicalGradient) { + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatConicalGradient); + // same old + GLfloat coeff[6] = { 1, 0, 0, + 0, 1, 0 }; + nvpr.programPathFragmentInputGen(mtl->prg, 0, GL_OBJECT_LINEAR_NV, 2, coeff); + + const QPointF centerPoint = d->fillGradient.a; + const GLfloat angle = -qDegreesToRadians(d->fillGradient.v0); + + f->glProgramUniform1f(mtl->prg, mtl->uniLoc[2], angle); + f->glProgramUniform2f(mtl->prg, mtl->uniLoc[3], centerPoint.x(), centerPoint.y()); + + spread = QQuickShapeGradient::RepeatSpread; + } else { + Q_UNREACHABLE(); + } + const QQuickShapeGradientCache::Key cacheKey(d->fillGradient.stops, spread); + QSGTexture *tx = QQuickShapeGradientCache::currentCache()->get(cacheKey); + tx->bind(); + } else { + mtl = mtlmgr.activateMaterial(QQuickNvprMaterialManager::MatSolid); + f->glProgramUniform4f(mtl->prg, mtl->uniLoc[0], + d->fillColor.x(), d->fillColor.y(), d->fillColor.z(), d->fillColor.w()); + } + f->glProgramUniform1f(mtl->prg, mtl->uniLoc[1], inheritedOpacity()); + + const int writeMask = 0xFF; + nvpr.stencilThenCoverFillPath(d->path, d->fillRule, writeMask, GL_BOUNDING_BOX_NV); +} + +void QQuickShapeNvprRenderNode::renderOffscreenFill(ShapePathRenderData *d) +{ + if (d->fallbackValid && d->fallbackFbo) + return; + + GLfloat bb[4]; + nvpr.getPathParameterfv(d->path, GL_PATH_STROKE_BOUNDING_BOX_NV, bb); + QSize sz = QSizeF(bb[2] - bb[0] + 1, bb[3] - bb[1] + 1).toSize(); + d->fallbackSize = QSize(qMax(32, sz.width()), qMax(32, sz.height())); + d->fallbackTopLeft = QPointF(bb[0], bb[1]); + + if (d->fallbackFbo && d->fallbackFbo->size() != d->fallbackSize) { + delete d->fallbackFbo; + d->fallbackFbo = nullptr; + } + if (!d->fallbackFbo) + d->fallbackFbo = new QOpenGLFramebufferObject(d->fallbackSize, QOpenGLFramebufferObject::CombinedDepthStencil); + if (!d->fallbackFbo->bind()) + return; + + GLint prevViewport[4]; + f->glGetIntegerv(GL_VIEWPORT, prevViewport); + + f->glViewport(0, 0, d->fallbackSize.width(), d->fallbackSize.height()); + f->glDisable(GL_DEPTH_TEST); + f->glClearColor(0, 0, 0, 0); + f->glClearStencil(0); + f->glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + f->glStencilFunc(GL_NOTEQUAL, 0, 0xFF); + f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + + QMatrix4x4 mv; + mv.translate(-d->fallbackTopLeft.x(), -d->fallbackTopLeft.y()); + nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, mv.constData()); + QMatrix4x4 proj; + proj.ortho(0, d->fallbackSize.width(), d->fallbackSize.height(), 0, 1, -1); + nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, proj.constData()); + + renderFill(d); + + d->fallbackFbo->release(); + f->glEnable(GL_DEPTH_TEST); + f->glViewport(prevViewport[0], prevViewport[1], prevViewport[2], prevViewport[3]); + + d->fallbackValid = true; +} + +void QQuickShapeNvprRenderNode::setupStencilForCover(bool stencilClip, int sv) +{ + if (!stencilClip) { + // 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->glStencilFunc(GL_NOTEQUAL, 0, 0xFF); + f->glStencilOp(GL_KEEP, GL_KEEP, GL_ZERO); + } else { + f->glStencilFunc(GL_LESS, sv, 0xFF); // pass if (sv & 0xFF) < (stencil_value & 0xFF) + f->glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); // dppass: replace with the original value (clip's stencil ref value) + } +} + +void QQuickShapeNvprRenderNode::render(const RenderState *state) +{ + f = QOpenGLContext::currentContext()->extraFunctions(); + + if (!nvprInited) { + if (!nvpr.create()) { + qWarning("NVPR init failed"); + return; + } + mtlmgr.create(&nvpr); + nvprInited = true; + } + + f->glUseProgram(0); + f->glStencilMask(~0); + f->glEnable(GL_STENCIL_TEST); + + const bool stencilClip = state->stencilEnabled(); + // when true, the stencil buffer already has a clip path with a ref value of sv + const int sv = state->stencilValue(); + const bool hasScissor = state->scissorEnabled(); + + if (hasScissor) { + // scissor rect is already set, just enable scissoring + f->glEnable(GL_SCISSOR_TEST); + } + + // 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); + + bool reloadMatrices = true; + + for (ShapePathRenderData &d : m_sp) { + updatePath(&d); + + const bool hasFill = d.hasFill(); + const bool hasStroke = d.hasStroke(); + + if (hasFill && stencilClip) { + // Fall back to a texture when complex clipping is in use and we have + // to fill. Reconciling glStencilFillPath's and the scenegraph's clip + // stencil semantics has not succeeded so far... + if (hasScissor) + f->glDisable(GL_SCISSOR_TEST); + renderOffscreenFill(&d); + reloadMatrices = true; + if (hasScissor) + f->glEnable(GL_SCISSOR_TEST); + } + + if (reloadMatrices) { + reloadMatrices = false; + nvpr.matrixLoadf(GL_PATH_MODELVIEW_NV, matrix()->constData()); + nvpr.matrixLoadf(GL_PATH_PROJECTION_NV, state->projectionMatrix()->constData()); + } + + // Fill! + if (hasFill) { + if (!stencilClip) { + setupStencilForCover(false, 0); + renderFill(&d); + } else { + if (!m_fallbackBlitter.isCreated()) + m_fallbackBlitter.create(); + f->glStencilFunc(GL_EQUAL, sv, 0xFF); + f->glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); + QMatrix4x4 mv = *matrix(); + mv.translate(d.fallbackTopLeft.x(), d.fallbackTopLeft.y()); + m_fallbackBlitter.texturedQuad(d.fallbackFbo->texture(), d.fallbackFbo->size(), + *state->projectionMatrix(), mv, + inheritedOpacity()); + } + } + + // Stroke! + if (hasStroke) { + const int strokeStencilValue = 0x80; + const int writeMask = 0x80; + + setupStencilForCover(stencilClip, sv); + if (stencilClip) { + // for the stencil step (eff. read mask == 0xFF & ~writeMask) + nvpr.pathStencilFunc(GL_EQUAL, sv, 0xFF); + // With stencilCLip == true the read mask for the stencil test before the stencil step is 0x7F. + // This assumes the clip stencil value is <= 127. + if (sv >= strokeStencilValue) + qWarning("Shape/NVPR: stencil clip ref value %d too large; expect rendering errors", sv); + } + + renderStroke(&d, strokeStencilValue, writeMask); + } + + if (stencilClip) + nvpr.pathStencilFunc(GL_ALWAYS, 0, ~0); + + d.dirty = 0; + } + + f->glBindProgramPipeline(0); +} + +QSGRenderNode::StateFlags QQuickShapeNvprRenderNode::changedStates() const +{ + return BlendState | StencilState | DepthState | ScissorState; +} + +QSGRenderNode::RenderingFlags QQuickShapeNvprRenderNode::flags() const +{ + return DepthAwareRendering; // avoid hitting the less optimal no-opaque-batch path in the renderer +} + +bool QQuickShapeNvprRenderNode::isSupported() +{ + static const bool nvprDisabled = qEnvironmentVariableIntValue("QT_NO_NVPR") != 0; + return !nvprDisabled && QQuickNvprFunctions::isSupported(); +} + +bool QQuickNvprBlitter::create() +{ + if (isCreated()) + destroy(); + + m_program = new QOpenGLShaderProgram; + if (QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile) { + m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/shapes/shaders/blit_core.vert")); + m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/shapes/shaders/blit_core.frag")); + } else { + m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/qt-project.org/shapes/shaders/blit.vert")); + m_program->addCacheableShaderFromSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/qt-project.org/shapes/shaders/blit.frag")); + } + m_program->bindAttributeLocation("qt_Vertex", 0); + m_program->bindAttributeLocation("qt_MultiTexCoord0", 1); + if (!m_program->link()) + return false; + + m_matrixLoc = m_program->uniformLocation("qt_Matrix"); + m_opacityLoc = m_program->uniformLocation("qt_Opacity"); + + m_buffer = new QOpenGLBuffer; + if (!m_buffer->create()) + return false; + m_buffer->bind(); + m_buffer->allocate(4 * sizeof(GLfloat) * 6); + m_buffer->release(); + + return true; +} + +void QQuickNvprBlitter::destroy() +{ + if (m_program) { + delete m_program; + m_program = nullptr; + } + if (m_buffer) { + delete m_buffer; + m_buffer = nullptr; + } +} + +void QQuickNvprBlitter::texturedQuad(GLuint textureId, const QSize &size, + const QMatrix4x4 &proj, const QMatrix4x4 &modelview, + float opacity) +{ + QOpenGLExtraFunctions *f = QOpenGLContext::currentContext()->extraFunctions(); + + m_program->bind(); + + QMatrix4x4 m = proj * modelview; + m_program->setUniformValue(m_matrixLoc, m); + m_program->setUniformValue(m_opacityLoc, opacity); + + m_buffer->bind(); + + if (size != m_prevSize) { + m_prevSize = size; + + QPointF p0(size.width() - 1, size.height() - 1); + QPointF p1(0, 0); + QPointF p2(0, size.height() - 1); + QPointF p3(size.width() - 1, 0); + + GLfloat vertices[6 * 4] = { + GLfloat(p0.x()), GLfloat(p0.y()), 1, 0, + GLfloat(p1.x()), GLfloat(p1.y()), 0, 1, + GLfloat(p2.x()), GLfloat(p2.y()), 0, 0, + + GLfloat(p0.x()), GLfloat(p0.y()), 1, 0, + GLfloat(p3.x()), GLfloat(p3.y()), 1, 1, + GLfloat(p1.x()), GLfloat(p1.y()), 0, 1, + }; + + m_buffer->write(0, vertices, sizeof(vertices)); + } + + m_program->enableAttributeArray(0); + m_program->enableAttributeArray(1); + f->glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), nullptr); + f->glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat), (const void *) (2 * sizeof(GLfloat))); + + f->glBindTexture(GL_TEXTURE_2D, textureId); + + f->glDrawArrays(GL_TRIANGLES, 0, 6); + + f->glBindTexture(GL_TEXTURE_2D, 0); + m_buffer->release(); + m_program->release(); +} + +QT_END_NAMESPACE diff --git a/src/quickshapes/qquickshapenvprrenderer_p.h b/src/quickshapes/qquickshapenvprrenderer_p.h new file mode 100644 index 0000000000..d40eb1bce9 --- /dev/null +++ b/src/quickshapes/qquickshapenvprrenderer_p.h @@ -0,0 +1,238 @@ +/**************************************************************************** +** +** 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 QQUICKSHAPENVPRRENDERER_P_H +#define QQUICKSHAPENVPRRENDERER_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 +#include +#include +#include +#include +#include +#include + +#if QT_CONFIG(opengl) + +QT_BEGIN_NAMESPACE + +class QQuickShapeNvprRenderNode; +class QOpenGLFramebufferObject; +class QOpenGLBuffer; +class QOpenGLExtraFunctions; + +class QQuickShapeNvprRenderer : public QQuickAbstractPathRenderer +{ +public: + enum Dirty { + DirtyPath = 0x01, + DirtyStyle = 0x02, + DirtyFillRule = 0x04, + DirtyDash = 0x08, + DirtyFillGradient = 0x10, + DirtyList = 0x20 + }; + + void beginSync(int totalCount) override; + void setPath(int index, const QQuickPath *path) override; + void setStrokeColor(int index, const QColor &color) override; + void setStrokeWidth(int index, qreal w) override; + void setFillColor(int index, const QColor &color) override; + void setFillRule(int index, QQuickShapePath::FillRule fillRule) override; + void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override; + void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override; + void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, + qreal dashOffset, const QVector &dashPattern) override; + void setFillGradient(int index, QQuickShapeGradient *gradient) override; + void endSync(bool async) override; + + void updateNode() override; + + void setNode(QQuickShapeNvprRenderNode *node); + + struct NvprPath { + QVector cmd; + QVector coord; + QByteArray str; + }; + +private: + struct ShapePathGuiData { + int dirty = 0; + NvprPath path; + qreal strokeWidth; + QColor strokeColor; + QColor fillColor; + QQuickShapePath::JoinStyle joinStyle; + int miterLimit; + QQuickShapePath::CapStyle capStyle; + QQuickShapePath::FillRule fillRule; + bool dashActive; + qreal dashOffset; + QVector dashPattern; + FillGradientType fillGradientActive; + GradientDesc fillGradient; + }; + + void convertPath(const QQuickPath *path, ShapePathGuiData *d); + + QQuickShapeNvprRenderNode *m_node = nullptr; + int m_accDirty = 0; + + QVector m_sp; +}; + +QDebug operator<<(QDebug debug, const QQuickShapeNvprRenderer::NvprPath &path); + +class QQuickNvprMaterialManager +{ +public: + enum Material { + MatSolid, + MatLinearGradient, + MatRadialGradient, + MatConicalGradient, + + NMaterials + }; + + struct MaterialDesc { + GLuint ppl = 0; + GLuint prg = 0; + int uniLoc[8]; + }; + + void create(QQuickNvprFunctions *nvpr); + MaterialDesc *activateMaterial(Material m); + void releaseResources(); + +private: + QQuickNvprFunctions *m_nvpr = nullptr; + MaterialDesc m_materials[NMaterials]; +}; + +class QQuickNvprBlitter +{ +public: + bool create(); + void destroy(); + bool isCreated() const { return m_program != nullptr; } + void texturedQuad(GLuint textureId, const QSize &size, + const QMatrix4x4 &proj, const QMatrix4x4 &modelview, + float opacity); + +private: + QOpenGLShaderProgram *m_program = nullptr; + QOpenGLBuffer *m_buffer = nullptr; + int m_matrixLoc = -1; + int m_opacityLoc = -1; + QSize m_prevSize; +}; + +class QQuickShapeNvprRenderNode : public QSGRenderNode +{ +public: + ~QQuickShapeNvprRenderNode(); + + void render(const RenderState *state) override; + void releaseResources() override; + StateFlags changedStates() const override; + RenderingFlags flags() const override; + + static bool isSupported(); + +private: + struct ShapePathRenderData { + GLuint path = 0; + int dirty = 0; + QQuickShapeNvprRenderer::NvprPath source; + GLfloat strokeWidth; + QVector4D strokeColor; + QVector4D fillColor; + GLenum joinStyle; + GLint miterLimit; + GLenum capStyle; + GLenum fillRule; + GLfloat dashOffset; + QVector dashPattern; + QQuickAbstractPathRenderer::FillGradientType fillGradientActive; + QQuickAbstractPathRenderer::GradientDesc fillGradient; + QOpenGLFramebufferObject *fallbackFbo = nullptr; + bool fallbackValid = false; + QSize fallbackSize; + QPointF fallbackTopLeft; + + bool hasFill() const { return !qFuzzyIsNull(fillColor.w()) || fillGradientActive; } + bool hasStroke() const { return strokeWidth >= 0.0f && !qFuzzyIsNull(strokeColor.w()); } + }; + + void updatePath(ShapePathRenderData *d); + void renderStroke(ShapePathRenderData *d, int strokeStencilValue, int writeMask); + void renderFill(ShapePathRenderData *d); + void renderOffscreenFill(ShapePathRenderData *d); + void setupStencilForCover(bool stencilClip, int sv); + + static bool nvprInited; + static QQuickNvprFunctions nvpr; + static QQuickNvprMaterialManager mtlmgr; + + QQuickNvprBlitter m_fallbackBlitter; + QOpenGLExtraFunctions *f = nullptr; + + QVector m_sp; + + friend class QQuickShapeNvprRenderer; +}; + +QT_END_NAMESPACE + +#endif // QT_CONFIG(opengl) + +#endif // QQUICKSHAPENVPRRENDERER_P_H diff --git a/src/quickshapes/qquickshapesglobal.h b/src/quickshapes/qquickshapesglobal.h new file mode 100644 index 0000000000..eb279c5d14 --- /dev/null +++ b/src/quickshapes/qquickshapesglobal.h @@ -0,0 +1,56 @@ +/**************************************************************************** +** +** Copyright (C) 2018 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#ifndef QQUICKSHAPESGLOBAL_H +#define QQUICKSHAPESGLOBAL_H + +#include + +QT_BEGIN_NAMESPACE + +#ifndef QT_STATIC +# if defined(QT_BUILD_QUICKSHAPES_LIB) +# define Q_QUICKSHAPES_EXPORT Q_DECL_EXPORT +# else +# define Q_QUICKSHAPES_EXPORT Q_DECL_IMPORT +# endif +#else +# define Q_QUICKSHAPES_EXPORT +#endif + +QT_END_NAMESPACE + +#endif // QQUICKSHAPESGLOBAL_H + diff --git a/src/quickshapes/qquickshapesglobal_p.h b/src/quickshapes/qquickshapesglobal_p.h new file mode 100644 index 0000000000..2f559b45a0 --- /dev/null +++ b/src/quickshapes/qquickshapesglobal_p.h @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2018 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 QQUICKSHAPESGLOBAL_P_H +#define QQUICKSHAPESGLOBAL_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 "qquickshapesglobal.h" + +QT_BEGIN_NAMESPACE + +#define Q_QUICKSHAPES_PRIVATE_EXPORT Q_QUICKSHAPES_EXPORT + +QT_END_NAMESPACE + + +#endif // QQUICKSHAPESGLOBAL_P_H diff --git a/src/quickshapes/qquickshapesoftwarerenderer.cpp b/src/quickshapes/qquickshapesoftwarerenderer.cpp new file mode 100644 index 0000000000..0f5c3604b5 --- /dev/null +++ b/src/quickshapes/qquickshapesoftwarerenderer.cpp @@ -0,0 +1,282 @@ +/**************************************************************************** +** +** 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 "qquickshapesoftwarerenderer_p.h" +#include + +QT_BEGIN_NAMESPACE + +void QQuickShapeSoftwareRenderer::beginSync(int totalCount) +{ + if (m_sp.count() != totalCount) { + m_sp.resize(totalCount); + m_accDirty |= DirtyList; + } +} + +void QQuickShapeSoftwareRenderer::setPath(int index, const QQuickPath *path) +{ + ShapePathGuiData &d(m_sp[index]); + d.path = path ? path->path() : QPainterPath(); + d.dirty |= DirtyPath; + m_accDirty |= DirtyPath; +} + +void QQuickShapeSoftwareRenderer::setStrokeColor(int index, const QColor &color) +{ + ShapePathGuiData &d(m_sp[index]); + d.pen.setColor(color); + d.dirty |= DirtyPen; + m_accDirty |= DirtyPen; +} + +void QQuickShapeSoftwareRenderer::setStrokeWidth(int index, qreal w) +{ + ShapePathGuiData &d(m_sp[index]); + d.strokeWidth = w; + if (w >= 0.0f) + d.pen.setWidthF(w); + d.dirty |= DirtyPen; + m_accDirty |= DirtyPen; +} + +void QQuickShapeSoftwareRenderer::setFillColor(int index, const QColor &color) +{ + ShapePathGuiData &d(m_sp[index]); + d.fillColor = color; + d.brush.setColor(color); + d.dirty |= DirtyBrush; + m_accDirty |= DirtyBrush; +} + +void QQuickShapeSoftwareRenderer::setFillRule(int index, QQuickShapePath::FillRule fillRule) +{ + ShapePathGuiData &d(m_sp[index]); + d.fillRule = Qt::FillRule(fillRule); + d.dirty |= DirtyFillRule; + m_accDirty |= DirtyFillRule; +} + +void QQuickShapeSoftwareRenderer::setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) +{ + ShapePathGuiData &d(m_sp[index]); + d.pen.setJoinStyle(Qt::PenJoinStyle(joinStyle)); + d.pen.setMiterLimit(miterLimit); + d.dirty |= DirtyPen; + m_accDirty |= DirtyPen; +} + +void QQuickShapeSoftwareRenderer::setCapStyle(int index, QQuickShapePath::CapStyle capStyle) +{ + ShapePathGuiData &d(m_sp[index]); + d.pen.setCapStyle(Qt::PenCapStyle(capStyle)); + d.dirty |= DirtyPen; + m_accDirty |= DirtyPen; +} + +void QQuickShapeSoftwareRenderer::setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, + qreal dashOffset, const QVector &dashPattern) +{ + ShapePathGuiData &d(m_sp[index]); + switch (strokeStyle) { + case QQuickShapePath::SolidLine: + d.pen.setStyle(Qt::SolidLine); + break; + case QQuickShapePath::DashLine: + d.pen.setStyle(Qt::CustomDashLine); + d.pen.setDashPattern(dashPattern); + d.pen.setDashOffset(dashOffset); + break; + default: + break; + } + d.dirty |= DirtyPen; + m_accDirty |= DirtyPen; +} + +static inline void setupPainterGradient(QGradient *painterGradient, const QQuickShapeGradient &g) +{ + painterGradient->setStops(g.gradientStops()); // sorted + switch (g.spread()) { + case QQuickShapeGradient::PadSpread: + painterGradient->setSpread(QGradient::PadSpread); + break; + case QQuickShapeGradient::RepeatSpread: + painterGradient->setSpread(QGradient::RepeatSpread); + break; + case QQuickShapeGradient::ReflectSpread: + painterGradient->setSpread(QGradient::ReflectSpread); + break; + default: + break; + } +} + +void QQuickShapeSoftwareRenderer::setFillGradient(int index, QQuickShapeGradient *gradient) +{ + ShapePathGuiData &d(m_sp[index]); + if (QQuickShapeLinearGradient *g = qobject_cast(gradient)) { + QLinearGradient painterGradient(g->x1(), g->y1(), g->x2(), g->y2()); + setupPainterGradient(&painterGradient, *g); + d.brush = QBrush(painterGradient); + } else if (QQuickShapeRadialGradient *g = qobject_cast(gradient)) { + QRadialGradient painterGradient(g->centerX(), g->centerY(), g->centerRadius(), + g->focalX(), g->focalY(), g->focalRadius()); + setupPainterGradient(&painterGradient, *g); + d.brush = QBrush(painterGradient); + } else if (QQuickShapeConicalGradient *g = qobject_cast(gradient)) { + QConicalGradient painterGradient(g->centerX(), g->centerY(), g->angle()); + setupPainterGradient(&painterGradient, *g); + d.brush = QBrush(painterGradient); + } else { + d.brush = QBrush(d.fillColor); + } + d.dirty |= DirtyBrush; + m_accDirty |= DirtyBrush; +} + +void QQuickShapeSoftwareRenderer::endSync(bool) +{ +} + +void QQuickShapeSoftwareRenderer::setNode(QQuickShapeSoftwareRenderNode *node) +{ + if (m_node != node) { + m_node = node; + m_accDirty |= DirtyList; + } +} + +void QQuickShapeSoftwareRenderer::updateNode() +{ + if (!m_accDirty) + return; + + const int count = m_sp.count(); + const bool listChanged = m_accDirty & DirtyList; + if (listChanged) + m_node->m_sp.resize(count); + + m_node->m_boundingRect = QRectF(); + + for (int i = 0; i < count; ++i) { + ShapePathGuiData &src(m_sp[i]); + QQuickShapeSoftwareRenderNode::ShapePathRenderData &dst(m_node->m_sp[i]); + + if (listChanged || (src.dirty & DirtyPath)) { + dst.path = src.path; + dst.path.setFillRule(src.fillRule); + } + + if (listChanged || (src.dirty & DirtyFillRule)) + dst.path.setFillRule(src.fillRule); + + if (listChanged || (src.dirty & DirtyPen)) { + dst.pen = src.pen; + dst.strokeWidth = src.strokeWidth; + } + + if (listChanged || (src.dirty & DirtyBrush)) + dst.brush = src.brush; + + src.dirty = 0; + + QRectF br = dst.path.boundingRect(); + const float sw = qMax(1.0f, dst.strokeWidth); + br.adjust(-sw, -sw, sw, sw); + m_node->m_boundingRect |= br; + } + + m_node->markDirty(QSGNode::DirtyMaterial); + m_accDirty = 0; +} + +QQuickShapeSoftwareRenderNode::QQuickShapeSoftwareRenderNode(QQuickShape *item) + : m_item(item) +{ +} + +QQuickShapeSoftwareRenderNode::~QQuickShapeSoftwareRenderNode() +{ + releaseResources(); +} + +void QQuickShapeSoftwareRenderNode::releaseResources() +{ +} + +void QQuickShapeSoftwareRenderNode::render(const RenderState *state) +{ + if (m_sp.isEmpty()) + return; + + QSGRendererInterface *rif = m_item->window()->rendererInterface(); + QPainter *p = static_cast(rif->getResource(m_item->window(), QSGRendererInterface::PainterResource)); + Q_ASSERT(p); + + const QRegion *clipRegion = state->clipRegion(); + if (clipRegion && !clipRegion->isEmpty()) + p->setClipRegion(*clipRegion, Qt::ReplaceClip); // must be done before setTransform + + p->setTransform(matrix()->toTransform()); + p->setOpacity(inheritedOpacity()); + + for (const ShapePathRenderData &d : qAsConst(m_sp)) { + p->setPen(d.strokeWidth >= 0.0f && d.pen.color() != Qt::transparent ? d.pen : Qt::NoPen); + p->setBrush(d.brush.color() != Qt::transparent ? d.brush : Qt::NoBrush); + p->drawPath(d.path); + } +} + +QSGRenderNode::StateFlags QQuickShapeSoftwareRenderNode::changedStates() const +{ + return nullptr; +} + +QSGRenderNode::RenderingFlags QQuickShapeSoftwareRenderNode::flags() const +{ + return BoundedRectRendering; // avoid fullscreen updates by saying we won't draw outside rect() +} + +QRectF QQuickShapeSoftwareRenderNode::rect() const +{ + return m_boundingRect; +} + +QT_END_NAMESPACE diff --git a/src/quickshapes/qquickshapesoftwarerenderer_p.h b/src/quickshapes/qquickshapesoftwarerenderer_p.h new file mode 100644 index 0000000000..11e658b4b7 --- /dev/null +++ b/src/quickshapes/qquickshapesoftwarerenderer_p.h @@ -0,0 +1,136 @@ +/**************************************************************************** +** +** 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 QQUICKSHAPESOFTWARERENDERER_P_H +#define QQUICKSHAPESOFTWARERENDERER_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 +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +class QQuickShapeSoftwareRenderNode; + +class QQuickShapeSoftwareRenderer : public QQuickAbstractPathRenderer +{ +public: + enum Dirty { + DirtyPath = 0x01, + DirtyPen = 0x02, + DirtyFillRule = 0x04, + DirtyBrush = 0x08, + DirtyList = 0x10 + }; + + void beginSync(int totalCount) override; + void setPath(int index, const QQuickPath *path) override; + void setStrokeColor(int index, const QColor &color) override; + void setStrokeWidth(int index, qreal w) override; + void setFillColor(int index, const QColor &color) override; + void setFillRule(int index, QQuickShapePath::FillRule fillRule) override; + void setJoinStyle(int index, QQuickShapePath::JoinStyle joinStyle, int miterLimit) override; + void setCapStyle(int index, QQuickShapePath::CapStyle capStyle) override; + void setStrokeStyle(int index, QQuickShapePath::StrokeStyle strokeStyle, + qreal dashOffset, const QVector &dashPattern) override; + void setFillGradient(int index, QQuickShapeGradient *gradient) override; + void endSync(bool async) override; + + void updateNode() override; + + void setNode(QQuickShapeSoftwareRenderNode *node); + +private: + QQuickShapeSoftwareRenderNode *m_node = nullptr; + int m_accDirty = 0; + struct ShapePathGuiData { + int dirty = 0; + QPainterPath path; + QPen pen; + float strokeWidth; + QColor fillColor; + QBrush brush; + Qt::FillRule fillRule; + }; + QVector m_sp; +}; + +class QQuickShapeSoftwareRenderNode : public QSGRenderNode +{ +public: + QQuickShapeSoftwareRenderNode(QQuickShape *item); + ~QQuickShapeSoftwareRenderNode(); + + void render(const RenderState *state) override; + void releaseResources() override; + StateFlags changedStates() const override; + RenderingFlags flags() const override; + QRectF rect() const override; + +private: + QQuickShape *m_item; + + struct ShapePathRenderData { + QPainterPath path; + QPen pen; + float strokeWidth; + QBrush brush; + }; + QVector m_sp; + QRectF m_boundingRect; + + friend class QQuickShapeSoftwareRenderer; +}; + +QT_END_NAMESPACE + +#endif // QQUICKSHAPESOFTWARERENDERER_P_H diff --git a/src/quickshapes/qtquickshapes.qrc b/src/quickshapes/qtquickshapes.qrc new file mode 100644 index 0000000000..f139861693 --- /dev/null +++ b/src/quickshapes/qtquickshapes.qrc @@ -0,0 +1,20 @@ + + + shaders/blit.vert + shaders/blit.frag + shaders/blit_core.frag + shaders/blit_core.vert + shaders/lineargradient.vert + shaders/lineargradient.frag + shaders/lineargradient_core.vert + shaders/lineargradient_core.frag + shaders/radialgradient.vert + shaders/radialgradient.frag + shaders/radialgradient_core.vert + shaders/radialgradient_core.frag + shaders/conicalgradient.vert + shaders/conicalgradient.frag + shaders/conicalgradient_core.vert + shaders/conicalgradient_core.frag + + diff --git a/src/quickshapes/quickshapes.pro b/src/quickshapes/quickshapes.pro new file mode 100644 index 0000000000..5a59dec18e --- /dev/null +++ b/src/quickshapes/quickshapes.pro @@ -0,0 +1,33 @@ +TARGET = QtQuickShapes + +QT = core gui-private qml quick-private + +CONFIG += simd optimize_full internal_module + +HEADERS += \ + qquickshapesglobal.h \ + qquickshapesglobal_p.h \ + qquickshape_p.h \ + qquickshape_p_p.h \ + qquickshapegenericrenderer_p.h \ + qquickshapesoftwarerenderer_p.h + +SOURCES += \ + qquickshape.cpp \ + qquickshapegenericrenderer.cpp \ + qquickshapesoftwarerenderer.cpp + +qtConfig(opengl) { + HEADERS += \ + qquicknvprfunctions_p.h \ + qquicknvprfunctions_p_p.h \ + qquickshapenvprrenderer_p.h + + SOURCES += \ + qquicknvprfunctions.cpp \ + qquickshapenvprrenderer.cpp +} + +RESOURCES += qtquickshapes.qrc + +load(qt_module) diff --git a/src/quickshapes/shaders/blit.frag b/src/quickshapes/shaders/blit.frag new file mode 100644 index 0000000000..505f0db179 --- /dev/null +++ b/src/quickshapes/shaders/blit.frag @@ -0,0 +1,9 @@ +varying highp vec2 qt_TexCoord0; + +uniform sampler2D source; +uniform lowp float qt_Opacity; + +void main() +{ + gl_FragColor = texture2D(source, qt_TexCoord0) * qt_Opacity; +} diff --git a/src/quickshapes/shaders/blit.vert b/src/quickshapes/shaders/blit.vert new file mode 100644 index 0000000000..f8306bd945 --- /dev/null +++ b/src/quickshapes/shaders/blit.vert @@ -0,0 +1,12 @@ +uniform highp mat4 qt_Matrix; + +attribute highp vec4 qt_Vertex; +attribute highp vec2 qt_MultiTexCoord0; + +varying highp vec2 qt_TexCoord0; + +void main() +{ + qt_TexCoord0 = qt_MultiTexCoord0; + gl_Position = qt_Matrix * qt_Vertex; +} diff --git a/src/quickshapes/shaders/blit_core.frag b/src/quickshapes/shaders/blit_core.frag new file mode 100644 index 0000000000..7073808fba --- /dev/null +++ b/src/quickshapes/shaders/blit_core.frag @@ -0,0 +1,13 @@ +#version 150 core + +in vec2 qt_TexCoord0; + +out vec4 fragColor; + +uniform sampler2D source; +uniform float qt_Opacity; + +void main() +{ + fragColor = texture(source, qt_TexCoord0) * qt_Opacity; +} diff --git a/src/quickshapes/shaders/blit_core.vert b/src/quickshapes/shaders/blit_core.vert new file mode 100644 index 0000000000..5246441da3 --- /dev/null +++ b/src/quickshapes/shaders/blit_core.vert @@ -0,0 +1,14 @@ +#version 150 core + +in vec4 qt_Vertex; +in vec2 qt_MultiTexCoord0; + +out vec2 qt_TexCoord0; + +uniform mat4 qt_Matrix; + +void main() +{ + qt_TexCoord0 = qt_MultiTexCoord0; + gl_Position = qt_Matrix * qt_Vertex; +} diff --git a/src/quickshapes/shaders/conicalgradient.frag b/src/quickshapes/shaders/conicalgradient.frag new file mode 100644 index 0000000000..af5fdd5ee0 --- /dev/null +++ b/src/quickshapes/shaders/conicalgradient.frag @@ -0,0 +1,19 @@ +#define INVERSE_2PI 0.1591549430918953358 + +uniform sampler2D gradTabTexture; +uniform lowp float opacity; + +uniform highp float angle; + +varying highp vec2 coord; + +void main() +{ + highp float t; + if (abs(coord.y) == abs(coord.x)) + t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI; + else + t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI; + gl_FragColor = texture2D(gradTabTexture, vec2(t - floor(t), 0.5)) * opacity; + +} diff --git a/src/quickshapes/shaders/conicalgradient.vert b/src/quickshapes/shaders/conicalgradient.vert new file mode 100644 index 0000000000..3350b0675a --- /dev/null +++ b/src/quickshapes/shaders/conicalgradient.vert @@ -0,0 +1,13 @@ +attribute vec4 vertexCoord; +attribute vec4 vertexColor; + +uniform mat4 matrix; +uniform vec2 translationPoint; + +varying vec2 coord; + +void main() +{ + coord = vertexCoord.xy - translationPoint; + gl_Position = matrix * vertexCoord; +} diff --git a/src/quickshapes/shaders/conicalgradient_core.frag b/src/quickshapes/shaders/conicalgradient_core.frag new file mode 100644 index 0000000000..e18b80159a --- /dev/null +++ b/src/quickshapes/shaders/conicalgradient_core.frag @@ -0,0 +1,22 @@ +#version 150 core + +#define INVERSE_2PI 0.1591549430918953358 + +uniform sampler2D gradTabTexture; +uniform float opacity; + +uniform float angle; + +in vec2 coord; + +out vec4 fragColor; + +void main() +{ + float t; + if (abs(coord.y) == abs(coord.x)) + t = (atan(-coord.y + 0.002, coord.x) + angle) * INVERSE_2PI; + else + t = (atan(-coord.y, coord.x) + angle) * INVERSE_2PI; + fragColor = texture(gradTabTexture, vec2(t - floor(t), 0.5)) * opacity; +} diff --git a/src/quickshapes/shaders/conicalgradient_core.vert b/src/quickshapes/shaders/conicalgradient_core.vert new file mode 100644 index 0000000000..f94a56401b --- /dev/null +++ b/src/quickshapes/shaders/conicalgradient_core.vert @@ -0,0 +1,15 @@ +#version 150 core + +in vec4 vertexCoord; +in vec4 vertexColor; + +uniform mat4 matrix; +uniform vec2 translationPoint; + +out vec2 coord; + +void main() +{ + coord = vertexCoord.xy - translationPoint; + gl_Position = matrix * vertexCoord; +} diff --git a/src/quickshapes/shaders/lineargradient.frag b/src/quickshapes/shaders/lineargradient.frag new file mode 100644 index 0000000000..7f4a739109 --- /dev/null +++ b/src/quickshapes/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/quickshapes/shaders/lineargradient.vert b/src/quickshapes/shaders/lineargradient.vert new file mode 100644 index 0000000000..eb21b8886b --- /dev/null +++ b/src/quickshapes/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/quickshapes/shaders/lineargradient_core.frag b/src/quickshapes/shaders/lineargradient_core.frag new file mode 100644 index 0000000000..5908acfa67 --- /dev/null +++ b/src/quickshapes/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/quickshapes/shaders/lineargradient_core.vert b/src/quickshapes/shaders/lineargradient_core.vert new file mode 100644 index 0000000000..60b56f38e3 --- /dev/null +++ b/src/quickshapes/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/quickshapes/shaders/radialgradient.frag b/src/quickshapes/shaders/radialgradient.frag new file mode 100644 index 0000000000..0f503bc0f7 --- /dev/null +++ b/src/quickshapes/shaders/radialgradient.frag @@ -0,0 +1,25 @@ +uniform sampler2D gradTabTexture; +uniform lowp float opacity; + +uniform highp vec2 focalToCenter; +uniform highp float centerRadius; +uniform highp float focalRadius; + +varying highp vec2 coord; + +void main() +{ + highp float rd = centerRadius - focalRadius; + highp float b = 2.0 * (rd * focalRadius + dot(coord, focalToCenter)); + highp float fmp2_m_radius2 = -focalToCenter.x * focalToCenter.x - focalToCenter.y * focalToCenter.y + rd * rd; + highp float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2); + highp float det = b * b - 4.0 * fmp2_m_radius2 * ((focalRadius * focalRadius) - dot(coord, coord)); + lowp vec4 result = vec4(0.0); + if (det >= 0.0) { + highp float detSqrt = sqrt(det); + highp float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); + if (focalRadius + w * (centerRadius - focalRadius) >= 0.0) + result = texture2D(gradTabTexture, vec2(w, 0.5)) * opacity; + } + gl_FragColor = result; +} diff --git a/src/quickshapes/shaders/radialgradient.vert b/src/quickshapes/shaders/radialgradient.vert new file mode 100644 index 0000000000..3350b0675a --- /dev/null +++ b/src/quickshapes/shaders/radialgradient.vert @@ -0,0 +1,13 @@ +attribute vec4 vertexCoord; +attribute vec4 vertexColor; + +uniform mat4 matrix; +uniform vec2 translationPoint; + +varying vec2 coord; + +void main() +{ + coord = vertexCoord.xy - translationPoint; + gl_Position = matrix * vertexCoord; +} diff --git a/src/quickshapes/shaders/radialgradient_core.frag b/src/quickshapes/shaders/radialgradient_core.frag new file mode 100644 index 0000000000..706ce53e4d --- /dev/null +++ b/src/quickshapes/shaders/radialgradient_core.frag @@ -0,0 +1,29 @@ +#version 150 core + +uniform sampler2D gradTabTexture; +uniform float opacity; + +uniform vec2 focalToCenter; +uniform float centerRadius; +uniform float focalRadius; + +in vec2 coord; + +out vec4 fragColor; + +void main() +{ + float rd = centerRadius - focalRadius; + float b = 2.0 * (rd * focalRadius + dot(coord, focalToCenter)); + float fmp2_m_radius2 = -focalToCenter.x * focalToCenter.x - focalToCenter.y * focalToCenter.y + rd * rd; + float inverse_2_fmp2_m_radius2 = 1.0 / (2.0 * fmp2_m_radius2); + float det = b * b - 4.0 * fmp2_m_radius2 * ((focalRadius * focalRadius) - dot(coord, coord)); + vec4 result = vec4(0.0); + if (det >= 0.0) { + float detSqrt = sqrt(det); + float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); + if (focalRadius + w * (centerRadius - focalRadius) >= 0.0) + result = texture(gradTabTexture, vec2(w, 0.5)) * opacity; + } + fragColor = result; +} diff --git a/src/quickshapes/shaders/radialgradient_core.vert b/src/quickshapes/shaders/radialgradient_core.vert new file mode 100644 index 0000000000..f94a56401b --- /dev/null +++ b/src/quickshapes/shaders/radialgradient_core.vert @@ -0,0 +1,15 @@ +#version 150 core + +in vec4 vertexCoord; +in vec4 vertexColor; + +uniform mat4 matrix; +uniform vec2 translationPoint; + +out vec2 coord; + +void main() +{ + coord = vertexCoord.xy - translationPoint; + gl_Position = matrix * vertexCoord; +} diff --git a/src/src.pro b/src/src.pro index 39127d7e10..92d79a9825 100644 --- a/src/src.pro +++ b/src/src.pro @@ -8,7 +8,8 @@ SUBDIRS += \ qtConfig(qml-animation) { SUBDIRS += \ - quick + quick \ + quickshapes qtConfig(testlib): \ SUBDIRS += qmltest @@ -30,3 +31,5 @@ qtConfig(qml-network) { QT_FOR_CONFIG += network qtConfig(localserver):qtConfig(qml-debug): SUBDIRS += qmldebug } + +DISTFILES += sync.profile configure.json diff --git a/sync.profile b/sync.profile index 5915e5e224..642942d152 100644 --- a/sync.profile +++ b/sync.profile @@ -1,6 +1,7 @@ %modules = ( # path to module name map "QtQml" => "$basedir/src/qml", "QtQuick" => "$basedir/src/quick", + "QtQuickShapes" => "$basedir/src/quickshapes", "QtQuickWidgets" => "$basedir/src/quickwidgets", "QtQuickParticles" => "$basedir/src/particles", "QtQuickTest" => "$basedir/src/qmltest", diff --git a/tests/auto/quick/qquickshape/qquickshape.pro b/tests/auto/quick/qquickshape/qquickshape.pro index 29c3502b86..a0e5c002e0 100644 --- a/tests/auto/quick/qquickshape/qquickshape.pro +++ b/tests/auto/quick/qquickshape/qquickshape.pro @@ -9,27 +9,5 @@ include (../shared/util.pri) TESTDATA = data/* -HEADERS += \ - ../../../../src/imports/shapes/qquickshape_p.h \ - ../../../../src/imports/shapes/qquickshape_p_p.h \ - ../../../../src/imports/shapes/qquickshapegenericrenderer_p.h \ - ../../../../src/imports/shapes/qquickshapesoftwarerenderer_p.h - -SOURCES += \ - ../../../../src/imports/shapes/qquickshape.cpp \ - ../../../../src/imports/shapes/qquickshapegenericrenderer.cpp \ - ../../../../src/imports/shapes/qquickshapesoftwarerenderer.cpp - -qtConfig(opengl) { - HEADERS += \ - ../../../../src/imports/shapes/qquicknvprfunctions_p.h \ - ../../../../src/imports/shapes/qquicknvprfunctions_p_p.h \ - ../../../../src/imports/shapes/qquickshapenvprrenderer_p.h - - SOURCES += \ - ../../../../src/imports/shapes/qquicknvprfunctions.cpp \ - ../../../../src/imports/shapes/qquickshapenvprrenderer.cpp -} - -QT += core-private gui-private qml-private quick-private testlib +QT += core-private gui-private qml-private quick-private testlib quickshapes-private qtHaveModule(widgets): QT += widgets diff --git a/tests/auto/quick/qquickshape/tst_qquickshape.cpp b/tests/auto/quick/qquickshape/tst_qquickshape.cpp index 2a349d2013..72f987ce4a 100644 --- a/tests/auto/quick/qquickshape/tst_qquickshape.cpp +++ b/tests/auto/quick/qquickshape/tst_qquickshape.cpp @@ -33,7 +33,7 @@ #include #include #include -#include "../../../../src/imports/shapes/qquickshape_p.h" +#include #include "../../shared/util.h" #include "../shared/viewtestutil.h" -- cgit v1.2.3