diff --git a/3rdParty/CMakeLists.txt b/3rdParty/CMakeLists.txt index 412ee63..f21ec0d 100644 --- a/3rdParty/CMakeLists.txt +++ b/3rdParty/CMakeLists.txt @@ -69,9 +69,6 @@ endif() # Define _UNICODE and UNICODE add_definitions(-D_UNICODE -DUNICODE) -# Define _USE_MATH_DEFINES -add_definitions(-D_USE_MATH_DEFINES) - # # # diff --git a/3rdParty/rive-runtime b/3rdParty/rive-runtime index 1880239..8a54c80 160000 --- a/3rdParty/rive-runtime +++ b/3rdParty/rive-runtime @@ -1 +1 @@ -Subproject commit 1880239f07eb44fd1231bb14525cfc26d0c8acdd +Subproject commit 8a54c80a217d2cc651c4d52385ceb6090ff8c6f1 diff --git a/examples/SimpleViewer/RiveInspectorView.qml b/examples/SimpleViewer/RiveInspectorView.qml index 261a126..b01dedf 100644 --- a/examples/SimpleViewer/RiveInspectorView.qml +++ b/examples/SimpleViewer/RiveInspectorView.qml @@ -153,10 +153,6 @@ Item { text: riveItem.frameRate font.pixelSize: 30 } - - onStateMachineStringInterfaceChanged: { - dynamicProperties.model = riveItem.stateMachineInterface.riveInputs - } } } } diff --git a/src/RiveQtQuickItem/RiveQtQuickPlugin.qmltypes b/src/RiveQtQuickItem/RiveQtQuickPlugin.qmltypes index 1e1dbeb..f6ee1e0 100644 --- a/src/RiveQtQuickItem/RiveQtQuickPlugin.qmltypes +++ b/src/RiveQtQuickItem/RiveQtQuickPlugin.qmltypes @@ -167,6 +167,7 @@ Module { exportMetaObjectRevisions: [256] Enum { name: "RivePropertyType" + isScoped: true type: "short" values: ["RiveNumber", "RiveBoolean", "RiveTrigger"] } diff --git a/src/RiveQtQuickItem/datatypes.h b/src/RiveQtQuickItem/datatypes.h index da20784..4deafa0 100644 --- a/src/RiveQtQuickItem/datatypes.h +++ b/src/RiveQtQuickItem/datatypes.h @@ -6,8 +6,6 @@ #pragma once -#include -#include #include struct AnimationInfo @@ -62,9 +60,9 @@ struct RiveRenderSettings public: enum RenderQuality { - Low, - Medium, - High + Low = 1, + Medium = 5, + High = 10 }; Q_ENUM(RenderQuality) diff --git a/src/RiveQtQuickItem/renderer/riveqtfactory.cpp b/src/RiveQtQuickItem/renderer/riveqtfactory.cpp index 02e7211..189b06b 100644 --- a/src/RiveQtQuickItem/renderer/riveqtfactory.cpp +++ b/src/RiveQtQuickItem/renderer/riveqtfactory.cpp @@ -1,79 +1,23 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // // SPDX-License-Identifier: LGPL-3.0-or-later -#include #include "renderer/riveqtfactory.h" -#include "renderer/riveqtfont.h" -#include "renderer/riveqtpainterrenderer.h" -#include "riveqsgrhirendernode.h" -#include "riveqsgsoftwarerendernode.h" #include "riveqtpath.h" -#include "rqqplogging.h" +#include "riveqtutils.h" -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -# include "renderer/riveqtrhirenderer.h" -#endif +#include -RiveQSGRenderNode *RiveQtFactory::renderNode(QQuickWindow *window, std::weak_ptr artboardInstance, - const QRectF &geometry) +RiveQtFactory::RiveQtFactory(RiveRenderSettings &renderSettings) + : rive::Factory() + , m_renderSettings(renderSettings) { - switch (window->rendererInterface()->graphicsApi()) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - case QSGRendererInterface::GraphicsApi::OpenGLRhi: - case QSGRendererInterface::GraphicsApi::MetalRhi: - case QSGRendererInterface::GraphicsApi::VulkanRhi: - case QSGRendererInterface::GraphicsApi::Direct3D11Rhi: { - auto sampleCount = 1; - QSGRendererInterface *renderInterface = window->rendererInterface(); - QRhi *rhi = static_cast(renderInterface->getResource(window, QSGRendererInterface::RhiResource)); - const QRhiSwapChain *swapChain = - static_cast(renderInterface->getResource(window, QSGRendererInterface::RhiSwapchainResource)); - - auto sampleCounts = rhi->supportedSampleCounts(); - - if (swapChain) { - sampleCount = swapChain->sampleCount(); - } else { - // maybe an offscreen render target is active; - // this is the case if the Rive scene is rendered - // inside an QQuickWidget - // try a different way to fetch the sample count - const auto redirectRenderTarget = - static_cast(renderInterface->getResource(window, QSGRendererInterface::RhiRedirectRenderTarget)); - if (redirectRenderTarget) { - sampleCount = redirectRenderTarget->sampleCount(); - } else { - qCritical(rqqpFactory) - << "Swap chain or offscreen render target not found for given window: rendering may be faulty."; - } - } - - if (sampleCount == 1 || (sampleCount > 1 - && rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer) - && sampleCounts.contains(sampleCount))) { - auto node = new RiveQSGRHIRenderNode(window, artboardInstance, geometry); - node->setFillMode(m_renderSettings.fillMode); - node->setPostprocessingMode(m_renderSettings.postprocessingMode); - return node; - } else { - qCritical(rqqpFactory) - << "MSAA requested, but requested sample size is not supported - requested sample size:" << sampleCount; - return nullptr; - } - } -#endif - case QSGRendererInterface::GraphicsApi::Software: - default: - return new RiveQSGSoftwareRenderNode(window, artboardInstance, geometry); - } } rive::rcp RiveQtFactory::makeRenderBuffer(rive::RenderBufferType renderBufferType, rive::RenderBufferFlags renderBufferFlags, size_t size) { - return rive::make_rcp(renderBufferType, renderBufferFlags, size);; + return rive::make_rcp(renderBufferType, renderBufferFlags, size); } rive::rcp RiveQtFactory::makeLinearGradient(float x1, float y1, float x2, float y2, const rive::ColorInt *colors, @@ -92,39 +36,12 @@ rive::rcp RiveQtFactory::makeRadialGradient(float centerX, f rive::rcp RiveQtFactory::makeRenderPath(rive::RawPath &rawPath, rive::FillRule fillRule) { - switch (renderType()) { - case RiveQtRenderType::QPainterRenderer: - return rive::make_rcp(rawPath, fillRule); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - case RiveQtRenderType::RHIRenderer: { - rive::rcp riveQtPath = rive::make_rcp(rawPath, fillRule); - riveQtPath->setLevelOfDetail(levelOfDetail()); - return riveQtPath; - } -#endif - - case RiveQtRenderType::None: - default: - return rive::make_rcp(rawPath, fillRule); // TODO Add Empty Path - } + return rive::make_rcp(rawPath, fillRule, m_renderSettings.renderQuality); } rive::rcp RiveQtFactory::makeEmptyRenderPath() { - switch (renderType()) { - case RiveQtRenderType::QPainterRenderer: - return rive::make_rcp(); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - case RiveQtRenderType::RHIRenderer: { - rive::rcp riveQtPath = rive::make_rcp(); - riveQtPath->setLevelOfDetail(levelOfDetail()); - return riveQtPath; - } -#endif - case RiveQtRenderType::None: - default: - return rive::make_rcp(); // TODO Add Empty Path - } + return rive::make_rcp(); } rive::rcp RiveQtFactory::makeRenderPaint() @@ -142,60 +59,3 @@ rive::rcp RiveQtFactory::decodeImage(rive::Span(new RiveQtImage(image)); } - -rive::rcp RiveQtFactory::decodeFont(rive::Span span) -{ -#ifdef WITH_RIVE_TEXT - return HBFont::Decode(span); -#else - return nullptr; -#endif - // Todo: would be nice to use qt build in support for fonts - // however qt is missing an api to access AXIS data from a font; lets for now use the HBFont maintained by rivecpp and consider - // switching later using qt directy would maybe allow us to drop the direct dependency on harfbuzz ... - - /*QByteArray fontData(reinterpret_cast(span.data()), static_cast(span.size())); - int fontId = QFontDatabase::addApplicationFontFromData(fontData); - - if (fontId == -1) { - return nullptr; - } - - const QStringList fontFamilies = QFontDatabase::applicationFontFamilies(fontId); - if (fontFamilies.isEmpty()) { - return nullptr; - } - - QFont font(fontFamilies.first()); - return rive::rcp(new RiveQtFont(font));*/ - -} - -unsigned int RiveQtFactory::levelOfDetail() -{ - switch (m_renderSettings.renderQuality) { - case RiveRenderSettings::Low: - return 1; - default: - case RiveRenderSettings::Medium: - return 5; - case RiveRenderSettings::High: - return 10; - } -} - -RiveQtFactory::RiveQtRenderType RiveQtFactory::renderType() -{ - switch (m_renderSettings.graphicsApi) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - case QSGRendererInterface::GraphicsApi::Direct3D11Rhi: - case QSGRendererInterface::GraphicsApi::OpenGLRhi: - case QSGRendererInterface::GraphicsApi::MetalRhi: - case QSGRendererInterface::GraphicsApi::VulkanRhi: - return RiveQtFactory::RiveQtRenderType::RHIRenderer; -#endif - case QSGRendererInterface::GraphicsApi::Software: - default: - return RiveQtFactory::RiveQtRenderType::QPainterRenderer; - } -} diff --git a/src/RiveQtQuickItem/renderer/riveqtfactory.h b/src/RiveQtQuickItem/renderer/riveqtfactory.h index d182a80..2465e9b 100644 --- a/src/RiveQtQuickItem/renderer/riveqtfactory.h +++ b/src/RiveQtQuickItem/renderer/riveqtfactory.h @@ -1,62 +1,30 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // // SPDX-License-Identifier: LGPL-3.0-or-later #pragma once -#include - -#include -#include -#include +#include +#include #include #include -#include - -#ifdef WITH_RIVE_TEXT -#include -#endif #include "datatypes.h" -#include "riveqsgrendernode.h" - -class RiveQtQuickItem; class RiveQtFactory : public rive::Factory { public: - enum class RiveQtRenderType : quint8 - { - None, - QPainterRenderer, - RHIRenderer - }; - - explicit RiveQtFactory(const RiveRenderSettings &renderSettings = RiveRenderSettings()) - : rive::Factory() - , m_renderSettings(renderSettings) - { - } + explicit RiveQtFactory(RiveRenderSettings &renderSettings); - void setRenderSettings(const RiveRenderSettings &renderSettings) { m_renderSettings = renderSettings; } - - RiveQSGRenderNode *renderNode(QQuickWindow *window, std::weak_ptr artboardInstance, const QRectF &geometry); rive::rcp makeRenderBuffer(rive::RenderBufferType, rive::RenderBufferFlags, size_t) override; - rive::rcp makeLinearGradient(float, float, float, float, const rive::ColorInt[], const float[], size_t) override; rive::rcp makeRadialGradient(float, float, float, const rive::ColorInt[], const float[], size_t) override; rive::rcp makeRenderPath(rive::RawPath &rawPath, rive::FillRule fillRule) override; rive::rcp makeEmptyRenderPath() override; rive::rcp makeRenderPaint() override; rive::rcp decodeImage(rive::Span span) override; - rive::rcp decodeFont(rive::Span span) override; private: - unsigned levelOfDetail(); - - RiveQtRenderType renderType(); - - RiveRenderSettings m_renderSettings; + RiveRenderSettings& m_renderSettings; }; diff --git a/src/RiveQtQuickItem/renderer/riveqtfont.cpp b/src/RiveQtQuickItem/renderer/riveqtfont.cpp index c0d9796..c40516e 100644 --- a/src/RiveQtQuickItem/renderer/riveqtfont.cpp +++ b/src/RiveQtQuickItem/renderer/riveqtfont.cpp @@ -3,10 +3,10 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -#include - #include "renderer/riveqtfont.h" +#include + RiveQtFont::RiveQtFont(const QFont &font, const QFontMetricsF &fontMetrics) : rive::Font({ static_cast(fontMetrics.ascent()), static_cast(fontMetrics.descent()) }) , m_font(font) diff --git a/src/RiveQtQuickItem/renderer/riveqtfont.h b/src/RiveQtQuickItem/renderer/riveqtfont.h index 8613b4b..f0f90e8 100644 --- a/src/RiveQtQuickItem/renderer/riveqtfont.h +++ b/src/RiveQtQuickItem/renderer/riveqtfont.h @@ -1,4 +1,3 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // @@ -6,6 +5,9 @@ #pragma once +#include +#include + #include #include #include @@ -15,9 +17,6 @@ #include #include -#include -#include - class RiveQtFont : public rive::Font, public std::enable_shared_from_this { diff --git a/src/RiveQtQuickItem/renderer/riveqtpainterrenderer.cpp b/src/RiveQtQuickItem/renderer/riveqtpainterrenderer.cpp index 48e34a2..acd4246 100644 --- a/src/RiveQtQuickItem/renderer/riveqtpainterrenderer.cpp +++ b/src/RiveQtQuickItem/renderer/riveqtpainterrenderer.cpp @@ -1,14 +1,12 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // // SPDX-License-Identifier: LGPL-3.0-or-later -#define _USE_MATH_DEFINES -#include - -#include "rqqplogging.h" #include "renderer/riveqtpainterrenderer.h" +#include "riveqtpath.h" +#include "rqqplogging.h" +#include "riveqtutils.h" RiveQtPainterRenderer::RiveQtPainterRenderer() : rive::Renderer() @@ -42,10 +40,10 @@ void RiveQtPainterRenderer::drawPath(rive::RenderPath *path, rive::RenderPaint * return; } - RiveQtPainterPath *qtPath = static_cast(path); + RiveQtPath *qtPath = static_cast(path); RiveQtPaint *qtPaint = static_cast(paint); - QPainter::CompositionMode compositionMode = convertRiveBlendModeToQCompositionMode(qtPaint->blendMode()); + QPainter::CompositionMode compositionMode = RiveQtUtils::convert(qtPaint->blendMode()); QPainter::RenderHints oldRenderHint = m_painter->renderHints(); m_painter->setCompositionMode(compositionMode); @@ -78,7 +76,7 @@ void RiveQtPainterRenderer::clipPath(rive::RenderPath *path) return; } - RiveQtPainterPath *qtPath = static_cast(path); + RiveQtPath *qtPath = static_cast(path); m_painter->setClipPath(qtPath->toQPainterPath(), Qt::ClipOperation::IntersectClip); } @@ -95,7 +93,7 @@ void RiveQtPainterRenderer::drawImage(const rive::RenderImage *image, rive::Blen return; } - QPainter::CompositionMode compositionMode = convertRiveBlendModeToQCompositionMode(blendMode); + QPainter::CompositionMode compositionMode = RiveQtUtils::convert(blendMode); QPainter::RenderHints oldRenderHint = m_painter->renderHints(); m_painter->setCompositionMode(compositionMode); m_painter->setRenderHint(QPainter::Antialiasing, true); @@ -122,41 +120,15 @@ void RiveQtPainterRenderer::drawImageMesh(const rive::RenderImage *image, rive:: qCWarning(rqqpRendering) << "Draw image mesh is not implemented for qpainter approach"; } -RiveQtPainterPath::RiveQtPainterPath(rive::RawPath &rawPath, rive::FillRule fillRule) +QImage RiveQtPainterRenderer::convertRiveImageToQImage(const rive::RenderImage *image) { - m_path.clear(); - m_path.setFillRule(RiveQtUtils::riveFillRuleToQt(fillRule)); - - for (const auto &[verb, pts] : rawPath) { - switch (verb) { - case rive::PathVerb::move: - m_path.moveTo(pts->x, pts->y); - break; - case rive::PathVerb::line: - m_path.lineTo(pts->x, pts->y); - break; - case rive::PathVerb::cubic: - m_path.cubicTo(pts[0].x, pts[0].y, pts[1].x, pts[1].y, pts[2].x, pts[2].y); - break; - case rive::PathVerb::close: - m_path.lineTo(pts->x, pts->y); - m_path.closeSubpath(); - break; - default: - break; - } - } -} - -void RiveQtPainterPath::addRenderPath(RenderPath *path, const rive::Mat2D &transform) -{ - if (!path) { - return; + if (!image) { + return QImage(); } - RiveQtPainterPath *qtPath = static_cast(path); - QTransform qTransform(transform[0], transform[1], transform[2], transform[3], transform[4], transform[5]); + // Cast the rive::RenderImage to RiveQtImage + const RiveQtImage *qtImage = static_cast(image); - QPainterPath qPath = qtPath->toQPainterPath() * qTransform; - m_path.addPath(qPath); + // Return the QImage contained in the RiveQtImage + return qtImage->image(); } diff --git a/src/RiveQtQuickItem/renderer/riveqtpainterrenderer.h b/src/RiveQtQuickItem/renderer/riveqtpainterrenderer.h index f3b82f3..e87ddbb 100644 --- a/src/RiveQtQuickItem/renderer/riveqtpainterrenderer.h +++ b/src/RiveQtQuickItem/renderer/riveqtpainterrenderer.h @@ -1,4 +1,3 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // @@ -6,73 +5,15 @@ #pragma once -#include -#include -#include -#include -#include - #include -#include - -#include "riveqtutils.h" - -class QPainterSubPath; -class RiveQtPainterSubPath; - -class RiveQtPainterPath : public rive::RenderPath -{ -public: - RiveQtPainterPath() = default; - RiveQtPainterPath(const RiveQtPainterPath &rqp) { m_path = rqp.m_path; } - RiveQtPainterPath(rive::RawPath &rawPath, rive::FillRule fillRule); - - void rewind() override { m_path.clear(); } - void moveTo(float x, float y) override { m_path.moveTo(x, y); } - void lineTo(float x, float y) override { m_path.lineTo(x, y); } - void cubicTo(float ox, float oy, float ix, float iy, float x, float y) override { m_path.cubicTo(ox, oy, ix, iy, x, y); } - void close() override { m_path.closeSubpath(); } - void fillRule(rive::FillRule value) override - { - switch (value) { - case rive::FillRule::evenOdd: - m_path.setFillRule(Qt::FillRule::OddEvenFill); - break; - case rive::FillRule::nonZero: - m_path.setFillRule(Qt::FillRule::WindingFill); - break; - } - } - void addRenderPath(RenderPath *path, const rive::Mat2D &transform) override; - void setQPainterPath(QPainterPath path) { m_path = path; } - - QPainterPath toQPainterPath() const { return m_path; } - std::vector pathes() const; - -private: - QPainterPath m_path; - std::vector m_subPaths; -}; -class RiveQtPainterSubPath -{ -private: - RiveQtPainterPath *m_path; - QTransform m_transform; - -public: - RiveQtPainterSubPath(RiveQtPainterPath *path, const QTransform &transform); - - RiveQtPainterPath *path() const; - QTransform transform() const; -}; +#include class RiveQtPainterRenderer : public rive::Renderer { public: RiveQtPainterRenderer(); - void setPainter(QPainter *painter); void save() override; void restore() override; void transform(const rive::Mat2D &transform) override; @@ -88,57 +29,11 @@ class RiveQtPainterRenderer : public rive::Renderer rive::BlendMode blendMode, float opacity) override; -private: - QImage convertRiveImageToQImage(const rive::RenderImage *image) - { - if (!image) { - return QImage(); - } - - // Cast the rive::RenderImage to RiveQtImage - const RiveQtImage *qtImage = static_cast(image); + void setPainter(QPainter *painter); - // Return the QImage contained in the RiveQtImage - return qtImage->image(); - } +private: + QImage convertRiveImageToQImage(const rive::RenderImage *image); - QPainter::CompositionMode convertRiveBlendModeToQCompositionMode(rive::BlendMode blendMode) - { - switch (blendMode) { - case rive::BlendMode::srcOver: - return QPainter::CompositionMode_SourceOver; - case rive::BlendMode::screen: - return QPainter::CompositionMode_Screen; - case rive::BlendMode::overlay: - return QPainter::CompositionMode_Overlay; - case rive::BlendMode::darken: - return QPainter::CompositionMode_Darken; - case rive::BlendMode::lighten: - return QPainter::CompositionMode_Lighten; - case rive::BlendMode::colorDodge: - return QPainter::CompositionMode_ColorDodge; - case rive::BlendMode::colorBurn: - return QPainter::CompositionMode_ColorBurn; - case rive::BlendMode::hardLight: - return QPainter::CompositionMode_HardLight; - case rive::BlendMode::softLight: - return QPainter::CompositionMode_SoftLight; - case rive::BlendMode::difference: - return QPainter::CompositionMode_Difference; - case rive::BlendMode::exclusion: - return QPainter::CompositionMode_Exclusion; - case rive::BlendMode::multiply: - return QPainter::CompositionMode_Multiply; - case rive::BlendMode::hue: - case rive::BlendMode::saturation: - case rive::BlendMode::color: - case rive::BlendMode::luminosity: - // QPainter doesn't have corresponding composition modes for these blend modes - return QPainter::CompositionMode_SourceOver; - default: - return QPainter::CompositionMode_SourceOver; - } - } QTransform m_transform; - QPainter *m_painter; + QPainter *m_painter { nullptr }; }; diff --git a/src/RiveQtQuickItem/renderer/riveqtrhirenderer.cpp b/src/RiveQtQuickItem/renderer/riveqtrhirenderer.cpp index d1fbb92..cecb013 100644 --- a/src/RiveQtQuickItem/renderer/riveqtrhirenderer.cpp +++ b/src/RiveQtQuickItem/renderer/riveqtrhirenderer.cpp @@ -1,23 +1,18 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // // SPDX-License-Identifier: LGPL-3.0-or-later -#define _USE_MATH_DEFINES -#include -#include +#include "renderer/riveqtrhirenderer.h" +#include "rhi/texturetargetnode.h" +#include "rqqplogging.h" +#include "riveqtpath.h" #include #include #include - #include -#include "rqqplogging.h" -#include "renderer/riveqtrhirenderer.h" -#include "rhi/texturetargetnode.h" - RiveQtRhiRenderer::RiveQtRhiRenderer(QQuickWindow *window, RiveQSGRHIRenderNode *node) : rive::Renderer() , m_window(window) @@ -28,11 +23,16 @@ RiveQtRhiRenderer::RiveQtRhiRenderer(QQuickWindow *window, RiveQSGRHIRenderNode RiveQtRhiRenderer::~RiveQtRhiRenderer() { - for (TextureTargetNode *textureTargetNode : m_renderNodes) { + for (TextureTargetNode *textureTargetNode : std::as_const(m_renderNodes)) { delete textureTargetNode; } } +void RiveQtRhiRenderer::setRiveRect(const QRectF &bounds) +{ + m_riveRect = bounds; +} + void RiveQtRhiRenderer::save() { m_rhiRenderStack.push_back(m_rhiRenderStack.back()); @@ -214,9 +214,9 @@ void RiveQtRhiRenderer::drawImageMesh(const rive::RenderImage *image, rive::rcp< node->updateClippingGeometry(clipResult.toVertices()); } -void RiveQtRhiRenderer::render(QRhiCommandBuffer *cb) +void RiveQtRhiRenderer::render(QRhiCommandBuffer *cb) const { - for (TextureTargetNode *textureTargetNode : m_renderNodes) { + for (TextureTargetNode *textureTargetNode : std::as_const(m_renderNodes)) { textureTargetNode->render(cb); } } @@ -225,7 +225,7 @@ TextureTargetNode *RiveQtRhiRenderer::getRiveDrawTargetNode() { TextureTargetNode *pathNode = nullptr; - for (TextureTargetNode *textureTargetNode : m_renderNodes) { + for (TextureTargetNode *textureTargetNode : std::as_const(m_renderNodes)) { if (textureTargetNode->isRecycled()) { pathNode = textureTargetNode; pathNode->take(); @@ -261,7 +261,7 @@ void RiveQtRhiRenderer::updateViewPort(const QRectF &viewportRect) void RiveQtRhiRenderer::recycleRiveNodes() { - for (TextureTargetNode *textureTargetNode : m_renderNodes) { + for (TextureTargetNode *textureTargetNode : std::as_const(m_renderNodes)) { textureTargetNode->recycle(); } } @@ -274,7 +274,7 @@ const QMatrix4x4 &RiveQtRhiRenderer::transformMatrix() const float RiveQtRhiRenderer::currentOpacity() { float opacity = 1.0; - for (const auto &renderState : m_rhiRenderStack) { + for (const auto &renderState : std::as_const(m_rhiRenderStack)) { opacity *= renderState.opacity; } return opacity; diff --git a/src/RiveQtQuickItem/renderer/riveqtrhirenderer.h b/src/RiveQtQuickItem/renderer/riveqtrhirenderer.h index 5d156eb..3abaffc 100644 --- a/src/RiveQtQuickItem/renderer/riveqtrhirenderer.h +++ b/src/RiveQtQuickItem/renderer/riveqtrhirenderer.h @@ -6,21 +6,15 @@ #pragma once #include -#include -#include -#include -#include - -#include +#include #include #include -#include "datatypes.h" -#include "riveqtpath.h" - -class RhiSubPath; +class QRhiCommandBuffer; class QSGRenderNode; +class QQuickWindow; +class RhiSubPath; class TextureTargetNode; class RiveQSGRHIRenderNode; @@ -37,7 +31,6 @@ class RiveQtRhiRenderer : public rive::Renderer public: RiveQtRhiRenderer(QQuickWindow *window, RiveQSGRHIRenderNode *node); virtual ~RiveQtRhiRenderer(); - void setRiveRect(const QRectF &bounds) { m_riveRect = bounds; } void save() override; void restore() override; @@ -53,8 +46,9 @@ class RiveQtRhiRenderer : public rive::Renderer void updateArtboardSize(const QSize &artboardSize) { m_artboardSize = artboardSize; } void updateViewPort(const QRectF &viewportRect); void recycleRiveNodes(); + void setRiveRect(const QRectF &bounds); - void render(QRhiCommandBuffer *cb); + void render(QRhiCommandBuffer *cb) const; private: TextureTargetNode *getRiveDrawTargetNode(); diff --git a/src/RiveQtQuickItem/renderer/riveqtutils.cpp b/src/RiveQtQuickItem/renderer/riveqtutils.cpp index 949d9ed..3342eed 100644 --- a/src/RiveQtQuickItem/renderer/riveqtutils.cpp +++ b/src/RiveQtQuickItem/renderer/riveqtutils.cpp @@ -1,25 +1,24 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // // SPDX-License-Identifier: LGPL-3.0-or-later -#include +#include "renderer/riveqtutils.h" +#include "rqqplogging.h" + #include +#include #include #include #include -#include "rqqplogging.h" -#include "renderer/riveqtutils.h" - -QColor RiveQtUtils::riveColorToQt(rive::ColorInt value) +QColor RiveQtUtils::convert(rive::ColorInt value) { return QColor::fromRgb(rive::colorRed(value), rive::colorGreen(value), rive::colorBlue(value), rive::colorAlpha(value)); } -Qt::PenJoinStyle RiveQtUtils::riveStrokeJoinToQt(rive::StrokeJoin join) +Qt::PenJoinStyle RiveQtUtils::convert(rive::StrokeJoin join) { switch (join) { case rive::StrokeJoin::miter: @@ -32,7 +31,7 @@ Qt::PenJoinStyle RiveQtUtils::riveStrokeJoinToQt(rive::StrokeJoin join) return Qt::PenJoinStyle::MiterJoin; } -Qt::PenCapStyle RiveQtUtils::riveStrokeCapToQt(rive::StrokeCap cap) +Qt::PenCapStyle RiveQtUtils::convert(rive::StrokeCap cap) { switch (cap) { case rive::StrokeCap::butt: @@ -45,13 +44,7 @@ Qt::PenCapStyle RiveQtUtils::riveStrokeCapToQt(rive::StrokeCap cap) return Qt::PenCapStyle::FlatCap; } -QMatrix4x4 RiveQtUtils::riveMat2DToQt(const rive::Mat2D &riveMatrix) -{ - return QMatrix4x4(riveMatrix[0], riveMatrix[1], 0, riveMatrix[4], riveMatrix[2], riveMatrix[3], 0, riveMatrix[5], 0, 0, 1, 0, 0, 0, 0, - 1); -} - -Qt::FillRule RiveQtUtils::riveFillRuleToQt(rive::FillRule fillRule) +Qt::FillRule RiveQtUtils::convert(rive::FillRule fillRule) { switch (fillRule) { case rive::FillRule::evenOdd: @@ -62,80 +55,80 @@ Qt::FillRule RiveQtUtils::riveFillRuleToQt(rive::FillRule fillRule) } } -QPainterPath RiveQtUtils::transformPathWithMatrix4x4(const QPainterPath &path, const QMatrix4x4 &matrix) +QPainter::CompositionMode RiveQtUtils::convert(rive::BlendMode blendMode) { - QPainterPath transformedPath; - - int count = path.elementCount(); - for (int i = 0; i < count; ++i) { - QPainterPath::Element element = path.elementAt(i); - QVector4D point(element.x, element.y, 0, 1); - QVector4D transformedPoint = matrix * point; - - switch (element.type) { - case QPainterPath::MoveToElement: - transformedPath.moveTo(transformedPoint.x(), transformedPoint.y()); - break; - case QPainterPath::LineToElement: - transformedPath.lineTo(transformedPoint.x(), transformedPoint.y()); - break; - case QPainterPath::CurveToElement: { - QPainterPath::Element controlPoint1 = element; - QPainterPath::Element controlPoint2 = path.elementAt(++i); - QPainterPath::Element endPoint = path.elementAt(++i); - - QVector4D ctrlPt1(controlPoint1.x, controlPoint1.y, 0, 1); - QVector4D ctrlPt2(controlPoint2.x, controlPoint2.y, 0, 1); - QVector4D endPt(endPoint.x, endPoint.y, 0, 1); - - QVector4D transformedCtrlPt1 = matrix * ctrlPt1; - QVector4D transformedCtrlPt2 = matrix * ctrlPt2; - QVector4D transformedEndPt = matrix * endPt; - - transformedPath.cubicTo(transformedCtrlPt1.x(), transformedCtrlPt1.y(), transformedCtrlPt2.x(), transformedCtrlPt2.y(), - transformedEndPt.x(), transformedEndPt.y()); - } break; - default: - break; - } + switch (blendMode) { + case rive::BlendMode::srcOver: + return QPainter::CompositionMode_SourceOver; + case rive::BlendMode::screen: + return QPainter::CompositionMode_Screen; + case rive::BlendMode::overlay: + return QPainter::CompositionMode_Overlay; + case rive::BlendMode::darken: + return QPainter::CompositionMode_Darken; + case rive::BlendMode::lighten: + return QPainter::CompositionMode_Lighten; + case rive::BlendMode::colorDodge: + return QPainter::CompositionMode_ColorDodge; + case rive::BlendMode::colorBurn: + return QPainter::CompositionMode_ColorBurn; + case rive::BlendMode::hardLight: + return QPainter::CompositionMode_HardLight; + case rive::BlendMode::softLight: + return QPainter::CompositionMode_SoftLight; + case rive::BlendMode::difference: + return QPainter::CompositionMode_Difference; + case rive::BlendMode::exclusion: + return QPainter::CompositionMode_Exclusion; + case rive::BlendMode::multiply: + return QPainter::CompositionMode_Multiply; + case rive::BlendMode::hue: + case rive::BlendMode::saturation: + case rive::BlendMode::color: + case rive::BlendMode::luminosity: + // QPainter doesn't have corresponding composition modes for these blend modes + return QPainter::CompositionMode_SourceOver; + default: + return QPainter::CompositionMode_SourceOver; } - - return transformedPath; } -RiveQtPaint::RiveQtPaint() { } +RiveQtPaint::RiveQtPaint() + : rive::RenderPaint() +{ +} void RiveQtPaint::color(rive::ColorInt value) { - m_color = RiveQtUtils::riveColorToQt(value); + m_color = RiveQtUtils::convert(value); m_opacity = rive::colorOpacity(value); if (!m_color.isValid()) { qCDebug(rqqpRendering) << "INVALID COLOR"; } - m_Brush.setColor(m_color); - m_Pen.setColor(m_color); + m_brush.setColor(m_color); + m_pen.setColor(m_color); } void RiveQtPaint::thickness(float value) { - m_Pen.setWidthF(value); + m_pen.setWidthF(value); } void RiveQtPaint::join(rive::StrokeJoin value) { - m_Pen.setJoinStyle(RiveQtUtils::riveStrokeJoinToQt(value)); + m_pen.setJoinStyle(RiveQtUtils::convert(value)); } void RiveQtPaint::cap(rive::StrokeCap value) { - m_Pen.setCapStyle(RiveQtUtils::riveStrokeCapToQt(value)); + m_pen.setCapStyle(RiveQtUtils::convert(value)); } void RiveQtPaint::blendMode(rive::BlendMode value) { - m_BlendMode = value; + m_blendMode = value; } void RiveQtPaint::style(rive::RenderPaintStyle value) @@ -144,17 +137,17 @@ void RiveQtPaint::style(rive::RenderPaintStyle value) switch (value) { case rive::RenderPaintStyle::fill: - m_Pen.setStyle(Qt::NoPen); - m_Brush.setStyle(Qt::SolidPattern); + m_pen.setStyle(Qt::NoPen); + m_brush.setStyle(Qt::SolidPattern); break; case rive::RenderPaintStyle::stroke: - m_Pen.setStyle(Qt::SolidLine); - m_Brush.setStyle(Qt::NoBrush); + m_pen.setStyle(Qt::SolidLine); + m_brush.setStyle(Qt::NoBrush); break; default: qCDebug(rqqpRendering) << "DEFAULT STYLE!"; - m_Pen.setStyle(Qt::NoPen); - m_Brush.setStyle(Qt::NoBrush); + m_pen.setStyle(Qt::NoPen); + m_brush.setStyle(Qt::NoBrush); break; } } @@ -164,19 +157,19 @@ void RiveQtPaint::shader(rive::rcp shader) m_shader = shader; if (shader) { RiveQtShader *qtShader = static_cast(shader.get()); - m_qtGradient = qtShader->gradient(); + m_gradient = qtShader->gradient(); - if (!m_qtGradient.isNull()) { - m_Brush = QBrush(*m_qtGradient); + if (!m_gradient.isNull()) { + m_brush = QBrush(*m_gradient); if (m_paintStyle == rive::RenderPaintStyle::stroke) { - m_Pen.setBrush(m_Brush); + m_pen.setBrush(m_brush); } } else { - m_Brush = QBrush(m_color); + m_brush = QBrush(m_color); } } else { - m_qtGradient.reset(); - m_Brush = QBrush(m_color); + m_gradient.reset(); + m_brush = QBrush(m_color); } } @@ -187,7 +180,7 @@ RiveQtLinearGradient::RiveQtLinearGradient(float x1, float y1, float x2, float y m_opacity = 0; for (size_t i = 0; i < count; ++i) { - QColor color = RiveQtUtils::riveColorToQt(colors[i]); + QColor color = RiveQtUtils::convert(colors[i]); m_opacity = qMax(m_opacity, rive::colorOpacity(colors[i])); qreal stop = stops[i]; m_gradient.setColorAt(stop, color); @@ -200,7 +193,7 @@ RiveQtRadialGradient::RiveQtRadialGradient(float centerX, float centerY, float r m_gradient = QRadialGradient(centerX, centerY, radius); for (size_t i = 0; i < count; i++) { - QColor color(RiveQtUtils::riveColorToQt(colors[i])); + QColor color(RiveQtUtils::convert(colors[i])); m_opacity = rive::colorOpacity(colors[i]); m_gradient.setColorAt(positions[i], color); } diff --git a/src/RiveQtQuickItem/renderer/riveqtutils.h b/src/RiveQtQuickItem/renderer/riveqtutils.h index 4b73bd1..dbd9257 100644 --- a/src/RiveQtQuickItem/renderer/riveqtutils.h +++ b/src/RiveQtQuickItem/renderer/riveqtutils.h @@ -1,4 +1,3 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // @@ -6,11 +5,6 @@ #pragma once -#include -#include -#include -#include - #include #include #include @@ -19,13 +13,17 @@ #include #include +#include +#include +#include +#include + namespace RiveQtUtils { -QColor riveColorToQt(rive::ColorInt value); -Qt::PenJoinStyle riveStrokeJoinToQt(rive::StrokeJoin join); -Qt::PenCapStyle riveStrokeCapToQt(rive::StrokeCap cap); -QMatrix4x4 riveMat2DToQt(const rive::Mat2D &riveMatrix); -Qt::FillRule riveFillRuleToQt(rive::FillRule fillRule); -QPainterPath transformPathWithMatrix4x4(const QPainterPath &path, const QMatrix4x4 &matrix); + QColor convert(rive::ColorInt value); + Qt::PenJoinStyle convert(rive::StrokeJoin join); + Qt::PenCapStyle convert(rive::StrokeCap cap); + Qt::FillRule convert(rive::FillRule fillRule); + QPainter::CompositionMode convert(rive::BlendMode blendMode); } class RiveQtImage : public rive::RenderImage @@ -38,7 +36,7 @@ class RiveQtImage : public rive::RenderImage m_Height = m_image.height(); } - const QImage &image() const { return m_image; } + QImage image() const { return m_image; } private: QImage m_image; @@ -51,6 +49,7 @@ class RiveQtShader : public rive::RenderShader virtual QSharedPointer gradient() const = 0; +protected: float m_opacity { 1.0 }; }; @@ -61,7 +60,7 @@ class RiveQtRadialGradient : public RiveQtShader QSharedPointer gradient() const override { return QSharedPointer::create(m_gradient); } - const QBrush &brush() const { return m_brush; } + QBrush brush() const { return m_brush; } private: QRadialGradient m_gradient; @@ -90,27 +89,27 @@ class RiveQtPaint : public rive::RenderPaint void cap(rive::StrokeCap value) override; void blendMode(rive::BlendMode value) override; void style(rive::RenderPaintStyle value) override; + void shader(rive::rcp shader) override; + void invalidateStroke() override {}; // maybe we need to reset something here + void feather(float value) override {}; rive::RenderPaintStyle paintStyle() const { return m_paintStyle; } - rive::BlendMode blendMode() const { return m_BlendMode; } - - const QColor &color() const { return m_color; } - const QBrush &brush() const { return m_Brush; } - const QPen &pen() const { return m_Pen; } - const float &opacity() const { return m_opacity; } + rive::BlendMode blendMode() const { return m_blendMode; } - virtual void shader(rive::rcp shader) override; - virtual void invalidateStroke() override {}; // maybe we need to reset something here + QColor color() const { return m_color; } + QBrush brush() const { return m_brush; } + QPen pen() const { return m_pen; } + float opacity() const { return m_opacity; } private: rive::RenderPaintStyle m_paintStyle; - rive::BlendMode m_BlendMode; + rive::BlendMode m_blendMode; QColor m_color; - QBrush m_Brush { Qt::NoBrush }; - QPen m_Pen { Qt::NoPen }; + QBrush m_brush { Qt::NoBrush }; + QPen m_pen { Qt::NoPen }; float m_opacity { 1.0 }; rive::rcp m_shader; - QSharedPointer m_qtGradient; + QSharedPointer m_gradient; }; diff --git a/src/RiveQtQuickItem/rhi/postprocessingsmaa.cpp b/src/RiveQtQuickItem/rhi/postprocessingsmaa.cpp index 5190647..1dee6dc 100644 --- a/src/RiveQtQuickItem/rhi/postprocessingsmaa.cpp +++ b/src/RiveQtQuickItem/rhi/postprocessingsmaa.cpp @@ -3,17 +3,15 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -#include - -#include -#include - #include "postprocessingsmaa.h" - // lookup textures #include "textures/AreaTex.h" #include "textures/SearchTex.h" +#include +#include +#include + // quad for our onscreen texture static float vertexData[] = { // Y up, CCW -1.0f, 1.0f, 0.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f diff --git a/src/RiveQtQuickItem/rhi/postprocessingsmaa.h b/src/RiveQtQuickItem/rhi/postprocessingsmaa.h index a055bef..b18b43c 100644 --- a/src/RiveQtQuickItem/rhi/postprocessingsmaa.h +++ b/src/RiveQtQuickItem/rhi/postprocessingsmaa.h @@ -7,12 +7,10 @@ #include #include - +#include #include #include -#include - class PostprocessingSMAA { public: diff --git a/src/RiveQtQuickItem/rhi/texturetargetnode.cpp b/src/RiveQtQuickItem/rhi/texturetargetnode.cpp index 2eb678a..9fb7286 100644 --- a/src/RiveQtQuickItem/rhi/texturetargetnode.cpp +++ b/src/RiveQtQuickItem/rhi/texturetargetnode.cpp @@ -4,13 +4,10 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "texturetargetnode.h" +#include "riveqsgrhirendernode.h" -#include -#include #include #include -#include "riveqsgrhirendernode.h" - #include #include @@ -209,13 +206,6 @@ void TextureTargetNode::prepareRender() m_cleanupList.append(m_drawPipelineResourceBindings); } - auto *uniformBuffer = m_drawUniformBuffer; - - // now we setup the shader to draw the path - float opacity = m_opacity; - - int useTexture = m_qImageTexture != nullptr && m_useTexture; // 76 - // note: the clipping path is provided in global coordinates, not local like the geometry // thats why we need to bind another matrix (without the transform) and thats why we have another UniformBuffer here! m_resourceUpdates->updateDynamicBuffer(m_clippingUniformBuffer, 0, 64, (*m_combinedMatrix).constData()); @@ -223,16 +213,15 @@ void TextureTargetNode::prepareRender() m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 0, 64, (*m_combinedMatrix).constData()); m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 784, 64, m_transform.constData()); - m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 64, 4, &opacity); - m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 76, 4, &useTexture); + float opacity = m_opacity; + m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 64, 4, &opacity); int useGradient = m_gradient != nullptr ? 1 : 0; // 72 m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 72, 4, &useGradient); + int useTexture = m_qImageTexture != nullptr && m_useTexture; // 76 + m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 76, 4, &useTexture); if (m_gradient) { - QVector gradientColors; // 144 - QVector gradientPositions; // 464 - m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 116, 4, &m_gradientData.gradientType); m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 68, 4, &m_gradientData.gradientRadius); m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 80, 4, &m_gradientData.gradientFocalPointX); m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 84, 4, &m_gradientData.gradientFocalPointY); @@ -243,6 +232,7 @@ void TextureTargetNode::prepareRender() m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 104, 4, &m_gradientData.endPointX); m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 108, 4, &m_gradientData.endPointY); m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 112, 4, &m_gradientData.numberOfStops); + m_resourceUpdates->updateDynamicBuffer(m_drawUniformBuffer, 116, 4, &m_gradientData.gradientType); int startStopColorsOffset = 144; int gradientPositionsOffset = 464; @@ -453,8 +443,10 @@ void TextureTargetNode::renderBlend(QRhiCommandBuffer *cb) QMatrix4x4 mvp = (*m_projectionMatrix); mvp.translate(-m_rect.x(), -m_rect.y()); int flipped = rhi->isYUpInFramebuffer() ? 1 : 0; + // NOTE: cast is required, since rive::BlendMode is 1 byte + int blendMode = static_cast(m_blendMode); m_blendResourceUpdates->updateDynamicBuffer(m_blendUniformBuffer, 0, 64, mvp.constData()); - m_blendResourceUpdates->updateDynamicBuffer(m_blendUniformBuffer, 64, 4, &m_blendMode); + m_blendResourceUpdates->updateDynamicBuffer(m_blendUniformBuffer, 64, 4, &blendMode); m_blendResourceUpdates->updateDynamicBuffer(m_blendUniformBuffer, 68, 4, &flipped); auto *currentDisplayBufferTarget = m_node->currentBlendTarget(); @@ -497,11 +489,10 @@ void TextureTargetNode::setClipping(const bool clip) void TextureTargetNode::setGradient(const QGradient *gradient) { m_gradient = gradient; - m_gradientData.gradientColors.clear(); - m_gradientData.gradientPositions.clear(); + m_gradientData = {}; QGradientStops gradientStops = gradient->stops(); - for (const auto &stop : gradientStops) { + for (const auto &stop : std::as_const(gradientStops)) { QColor color = stop.second; m_gradientData.gradientColors.append(color); m_gradientData.gradientPositions.append(QVector2D(stop.first, 0.0f)); @@ -536,8 +527,6 @@ void TextureTargetNode::setTexture(const QImage &image, bool recreate, const QMatrix4x4 &transform) { - - LITE_RTTI_CAST_OR_RETURN(cgIndices, rive::DataRenderBuffer*, indices.get()); LITE_RTTI_CAST_OR_RETURN(cgVertices, rive::DataRenderBuffer*, vertices.get()); LITE_RTTI_CAST_OR_RETURN(cgUvCoords, rive::DataRenderBuffer*, uvCoords.get()); diff --git a/src/RiveQtQuickItem/rhi/texturetargetnode.h b/src/RiveQtQuickItem/rhi/texturetargetnode.h index 1aaf196..49663ca 100644 --- a/src/RiveQtQuickItem/rhi/texturetargetnode.h +++ b/src/RiveQtQuickItem/rhi/texturetargetnode.h @@ -65,7 +65,6 @@ class TextureTargetNode bool recreate, const QMatrix4x4 &transform); - int blendMode() const { return (int)m_blendMode; } void setBlendMode(rive::BlendMode blendMode); void updateGeometry(const QVector> &geometry, const QMatrix4x4 &transform); @@ -159,17 +158,17 @@ class TextureTargetNode struct GradientData { - float gradientRadius; // 68 - float gradientFocalPointX; // 80 - float gradientFocalPointY; // 84 - float gradientCenterX; // 88 - float gradientCenterY; // 92 - float startPointX; // 96 - float startPointY; // 100 - float endPointX; // 104 - float endPointY; // 108 - int numberOfStops; // 112 - int gradientType; // 116 + float gradientRadius = 0.0; // 68 + float gradientFocalPointX = 0.0; // 80 + float gradientFocalPointY = 0.0; // 84 + float gradientCenterX = 0.0; // 88 + float gradientCenterY = 0.0; // 92 + float startPointX = 0.0; // 96 + float startPointY = 0.0; // 100 + float endPointX = 0.0; // 104 + float endPointY = 0.0; // 108 + int numberOfStops = 0; // 112 + int gradientType = -1; // 116 QVector gradientColors; // 144 QVector gradientPositions; // 464 diff --git a/src/RiveQtQuickItem/riveqsgrendernode.cpp b/src/RiveQtQuickItem/riveqsgrendernode.cpp index 513cd11..60f9779 100644 --- a/src/RiveQtQuickItem/riveqsgrendernode.cpp +++ b/src/RiveQtQuickItem/riveqsgrendernode.cpp @@ -4,17 +4,10 @@ // SPDX-License-Identifier: LGPL-3.0-or-later #include "riveqsgrendernode.h" -#include "riveqtquickitem.h" +#include "riveqsgrhirendernode.h" +#include "riveqsgsoftwarerendernode.h" -QRectF RiveQSGRenderNode::rect() const -{ - return m_rect; -} - -RiveQSGRenderNode::RiveQSGRenderNode(QQuickWindow *window, std::weak_ptr artboardInstance, const QRectF &geometry) - : RiveQSGBaseNode(window, artboardInstance, geometry) -{ -} +#include RiveQSGBaseNode::RiveQSGBaseNode(QQuickWindow *window, std::weak_ptr artboardInstance, const QRectF &geometry) : m_artboardInstance(artboardInstance) @@ -43,6 +36,11 @@ float RiveQSGBaseNode::scaleFactorY() const return m_scaleFactorY; } +void RiveQSGBaseNode::updateArtboardInstance(std::weak_ptr artboardInstance) +{ + m_artboardInstance = artboardInstance; +} + void RiveQSGBaseNode::setArtboardRect(const QRectF &bounds) { m_topLeftRivePosition = bounds.topLeft(); @@ -53,3 +51,23 @@ void RiveQSGBaseNode::setArtboardRect(const QRectF &bounds) m_scaleFactorY = bounds.height() / artboardInstance->height(); } } + +RiveQSGRenderNode::RiveQSGRenderNode(QQuickWindow *window, std::weak_ptr artboardInstance, const QRectF &geometry) + : RiveQSGBaseNode(window, artboardInstance, geometry) +{ +} + +QSGRenderNode::RenderingFlags RiveQSGRenderNode::flags() const +{ + return QSGRenderNode::BoundedRectRendering | QSGRenderNode::DepthAwareRendering; +} + +QSGRenderNode::StateFlags RiveQSGRenderNode::changedStates() const +{ + return QSGRenderNode::BlendState; +} + +QRectF RiveQSGRenderNode::rect() const +{ + return m_rect; +} diff --git a/src/RiveQtQuickItem/riveqsgrendernode.h b/src/RiveQtQuickItem/riveqsgrendernode.h index eff6f00..e3444e7 100644 --- a/src/RiveQtQuickItem/riveqsgrendernode.h +++ b/src/RiveQtQuickItem/riveqsgrendernode.h @@ -5,13 +5,14 @@ #pragma once -#include -#include -#include +#include + #include -#include +#include -#include +#include "datatypes.h" + +class QQuickWindow; class RiveQSGBaseNode { @@ -24,7 +25,7 @@ class RiveQSGBaseNode virtual float scaleFactorX() const; virtual float scaleFactorY() const; - virtual void updateArtboardInstance(std::weak_ptr artboardInstance) { m_artboardInstance = artboardInstance; } + virtual void updateArtboardInstance(std::weak_ptr artboardInstance); virtual void setArtboardRect(const QRectF &bounds); @@ -33,7 +34,7 @@ class RiveQSGBaseNode QRectF m_rect; QPointF m_topLeftRivePosition { 0.f, 0.f }; QSizeF m_riveSize { 0.f, 0.f }; - QQuickWindow *m_window; + QQuickWindow *m_window { nullptr }; float m_scaleFactorX { 1.0f }; float m_scaleFactorY { 1.0f }; @@ -44,7 +45,7 @@ class RiveQSGRenderNode : public QSGRenderNode, public RiveQSGBaseNode public: RiveQSGRenderNode(QQuickWindow *window, std::weak_ptr artboardInstance, const QRectF &geometry); - StateFlags changedStates() const override { return QSGRenderNode::BlendState; } - RenderingFlags flags() const override { return QSGRenderNode::BoundedRectRendering | QSGRenderNode::DepthAwareRendering; } + StateFlags changedStates() const override; + RenderingFlags flags() const override; QRectF rect() const override; }; diff --git a/src/RiveQtQuickItem/riveqsgrhirendernode.cpp b/src/RiveQtQuickItem/riveqsgrhirendernode.cpp index fcd7d56..6ae3fc6 100644 --- a/src/RiveQtQuickItem/riveqsgrhirendernode.cpp +++ b/src/RiveQtQuickItem/riveqsgrhirendernode.cpp @@ -3,23 +3,18 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later +#include "riveqsgrhirendernode.h" +#include "riveqtquickitem.h" +#include "renderer/riveqtrhirenderer.h" +#include "rhi/postprocessingsmaa.h" +#include "rqqplogging.h" + #include #include - #include #include #include - -#include #include -#include - -#include "riveqsgrhirendernode.h" -#include "riveqtquickitem.h" -#include "renderer/riveqtrhirenderer.h" - -#include "rhi/postprocessingsmaa.h" -#include "rqqplogging.h" RiveQSGRHIRenderNode::RiveQSGRHIRenderNode(QQuickWindow *window, std::weak_ptr artboardInstance, const QRectF &geometry) @@ -212,7 +207,7 @@ void RiveQSGRHIRenderNode::render(const RenderState *state) } if (!commandBuffer) { - qCritical(rqqpFactory) << "Render: No command buffer available"; + qCCritical(rqqpFactory) << "Render: No command buffer available"; return; } @@ -340,6 +335,50 @@ bool RiveQSGRHIRenderNode::isCurrentRenderBufferA() return m_currentRenderSurface == &m_renderSurfaceA; } +RiveQSGRHIRenderNode *RiveQSGRHIRenderNode::create(const RiveRenderSettings &renderSettings, + QQuickWindow *window, + std::weak_ptr artboardInstance, + const QRectF &geometry) +{ + auto sampleCount = 1; + QSGRendererInterface *renderInterface = window->rendererInterface(); + QRhi *rhi = static_cast(renderInterface->getResource(window, QSGRendererInterface::RhiResource)); + const QRhiSwapChain *swapChain = + static_cast(renderInterface->getResource(window, QSGRendererInterface::RhiSwapchainResource)); + + auto sampleCounts = rhi->supportedSampleCounts(); + + if (swapChain) { + sampleCount = swapChain->sampleCount(); + } else { + // maybe an offscreen render target is active; + // this is the case if the Rive scene is rendered + // inside an QQuickWidget + // try a different way to fetch the sample count + const auto redirectRenderTarget = + static_cast(renderInterface->getResource(window, QSGRendererInterface::RhiRedirectRenderTarget)); + if (redirectRenderTarget) { + sampleCount = redirectRenderTarget->sampleCount(); + } else { + qCCritical(rqqpFactory) + << "Swap chain or offscreen render target not found for given window: rendering may be faulty."; + } + } + + if (sampleCount == 1 || (sampleCount > 1 + && rhi->isFeatureSupported(QRhi::MultisampleRenderBuffer) + && sampleCounts.contains(sampleCount))) { + auto node = new RiveQSGRHIRenderNode(window, artboardInstance, geometry); + node->setFillMode(renderSettings.fillMode); + node->setPostprocessingMode(renderSettings.postprocessingMode); + return node; + } else { + qCCritical(rqqpFactory) + << "MSAA requested, but requested sample size is not supported - requested sample size:" << sampleCount; + return nullptr; + } +} + #ifdef OPENGL_DEBUG void GLAPIENTRY MessageCallback( GLenum source, @@ -387,7 +426,7 @@ void RiveQSGRHIRenderNode::prepare() } if (!commandBuffer) { - qCritical(rqqpFactory) << "Prepare: No command buffer available"; + qCCritical(rqqpFactory) << "Prepare: No command buffer available"; return; } @@ -533,7 +572,7 @@ void RiveQSGRHIRenderNode::prepare() auto artboardInstance = m_artboardInstance.lock(); if (!m_renderer) { - qWarning() << "Renderer is null"; + qCWarning(rqqpRendering) << "Renderer is null"; return; } @@ -915,7 +954,7 @@ bool RiveQSGRHIRenderNode::RenderSurface::create(QRhi *rhi, int samples, const Q const bool renderInMsaaBuffer = samples > 1 && !isMetal; if (isMetal && samples > 1) { - qWarning(rqqpRendering) << "MSAA on RHI Metal is not supported yet; If you need AA, set postprocessingMode to RiveQtQuickItem.SMAA"; + qCWarning(rqqpRendering) << "MSAA on RHI Metal is not supported yet; If you need AA, set postprocessingMode to RiveQtQuickItem.SMAA"; } bool textureCreated = false; diff --git a/src/RiveQtQuickItem/riveqsgrhirendernode.h b/src/RiveQtQuickItem/riveqsgrhirendernode.h index 8e80e84..b65f216 100644 --- a/src/RiveQtQuickItem/riveqsgrhirendernode.h +++ b/src/RiveQtQuickItem/riveqsgrhirendernode.h @@ -5,24 +5,15 @@ #pragma once +#include "riveqsgrendernode.h" +#include "datatypes.h" + #include -#include -#include -#include #include -#include - #include -#include #include -#include "datatypes.h" -#include "riveqsgrendernode.h" - -//----------------- -class RiveQtQuickItem; -class TextureTargetNode; class RiveQtRhiRenderer; class PostprocessingSMAA; @@ -65,6 +56,11 @@ class RiveQSGRHIRenderNode : public RiveQSGRenderNode bool isCurrentRenderBufferA(); + static RiveQSGRHIRenderNode *create(const RiveRenderSettings &renderSettings, + QQuickWindow *window, + std::weak_ptr artboardInstance, + const QRectF &geometry); + protected: struct RenderSurface { diff --git a/src/RiveQtQuickItem/riveqsgsoftwarerendernode.cpp b/src/RiveQtQuickItem/riveqsgsoftwarerendernode.cpp index aba2f30..3a46d1e 100644 --- a/src/RiveQtQuickItem/riveqsgsoftwarerendernode.cpp +++ b/src/RiveQtQuickItem/riveqsgsoftwarerendernode.cpp @@ -1,14 +1,12 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // // SPDX-License-Identifier: LGPL-3.0-or-later -#include - -#include "riveqtquickitem.h" #include "riveqsgsoftwarerendernode.h" +#include + RiveQSGSoftwareRenderNode::RiveQSGSoftwareRenderNode(QQuickWindow *window, std::weak_ptr artboardInstance, const QRectF &geometry) : RiveQSGRenderNode(window, artboardInstance, geometry) @@ -20,87 +18,18 @@ QRectF RiveQSGSoftwareRenderNode::rect() const return QRectF(0, 0, m_rect.width(), m_rect.height()); } -void RiveQSGSoftwareRenderNode::render(const RenderState *state) -{ - renderSoftware(state); -} - -void RiveQSGSoftwareRenderNode::paint(QPainter *painter) +QSGRenderNode::RenderingFlags RiveQSGSoftwareRenderNode::flags() const { - if (!painter) { - return; - } - - if (m_artboardInstance.expired()) { - return; - } - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - auto artboardInstance = m_artboardInstance.lock(); - - auto x = 0; - auto y = 0; - - auto aspectX = painter->device()->width() / (artboardInstance->width()); - auto aspectY = painter->device()->height() / (artboardInstance->height()); - - // Calculate the uniform scale factor to preserve the aspect ratio - auto scaleFactor = qMin(aspectX, aspectY); - - // Calculate the new width and height of the item while preserving the aspect ratio - auto newWidth = artboardInstance->width() * scaleFactor; - auto newHeight = artboardInstance->height() * scaleFactor; - - // Calculate the offsets needed to center the item within its bounding rectangle - auto offsetX = (painter->device()->width() - newWidth) / 2.0; - auto offsetY = (painter->device()->height() - newHeight) / 2.0; - - // TODO this only works for PreserverAspectFit - m_scaleFactorX = scaleFactor; - m_scaleFactorY = scaleFactor; - m_topLeftRivePosition.setX(offsetX); - m_topLeftRivePosition.setY(offsetY); - - m_modelViewTransform = QTransform(); - // Apply transformations in the correct order - m_modelViewTransform.translate(x, y); - m_modelViewTransform.translate(offsetX, offsetY); - m_modelViewTransform.scale(scaleFactor, scaleFactor); -#endif - - painter->save(); - { - auto artboardInstance = m_artboardInstance.lock(); - - painter->setTransform(m_modelViewTransform, false); - - m_renderer.setPainter(painter); - - painter->save(); - { - if (artboardInstance) { - artboardInstance->draw(&m_renderer); - } - } - painter->restore(); - } - painter->restore(); + return QSGRenderNode::BoundedRectRendering; } -QTransform matrix4x4ToTransform(const QMatrix4x4 &matrix) +QSGRenderNode::StateFlags RiveQSGSoftwareRenderNode::changedStates() const { - return QTransform(matrix(0, 0), matrix(0, 1), matrix(0, 3), matrix(1, 0), matrix(1, 1), matrix(1, 3), matrix(3, 0), matrix(3, 1), - matrix(3, 3)); + return QSGRenderNode::BlendState; } -void RiveQSGSoftwareRenderNode::renderSoftware(const RenderState *state) +void RiveQSGSoftwareRenderNode::render(const RenderState *state) { - -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) - if (m_artboardInstance.expired()) { - return; - } - if (!m_window) { return; } @@ -110,50 +39,53 @@ void RiveQSGSoftwareRenderNode::renderSoftware(const RenderState *state) return; } - auto artboardInstance = m_artboardInstance.lock(); + QPainter *painter = nullptr; - const QRect &boundingRect = state->clipRegion()->boundingRect(); + void *vPainter = renderInterface->getResource(m_window, QSGRendererInterface::Resource::PainterResource); + if (vPainter) { + painter = static_cast(vPainter); + } else { + return; + } - auto x = boundingRect.x(); - auto y = boundingRect.y(); + paint(painter, state->clipRegion()->boundingRect(), state->projectionMatrix()->toTransform()); +} - auto aspectX = boundingRect.width() / (artboardInstance->width()); - auto aspectY = boundingRect.height() / (artboardInstance->height()); +void RiveQSGSoftwareRenderNode::paint(QPainter *painter, const QRect &bounds, const QTransform &transform) +{ + if (m_artboardInstance.expired()) { + return; + } + const auto artboardInstance = m_artboardInstance.lock(); + const QSizeF artboardSize(artboardInstance->width(), artboardInstance->height()); + const auto aspectX = bounds.width() / artboardSize.width(); + const auto aspectY = bounds.height() / artboardSize.height(); // Calculate the uniform scale factor to preserve the aspect ratio - auto scaleFactor = qMin(aspectX, aspectY); - + const auto scaleFactor = qMin(aspectX, aspectY); // Calculate the new width and height of the item while preserving the aspect ratio - auto newWidth = artboardInstance->width() * scaleFactor; - auto newHeight = artboardInstance->height() * scaleFactor; - + const QSizeF newSize = artboardSize * scaleFactor; // Calculate the offsets needed to center the item within its bounding rectangle - auto offsetX = (boundingRect.width() - newWidth) / 2.0; - auto offsetY = (boundingRect.height() - newHeight) / 2.0; + const auto offsetX = (bounds.width() - newSize.width()) / 2.0; + const auto offsetY = (bounds.height() - newSize.height()) / 2.0; - // TODO this only works for PreserverAspectFit + // TODO this only works for PreserveAspectFit m_scaleFactorX = scaleFactor; m_scaleFactorY = scaleFactor; m_topLeftRivePosition.setX(offsetX); m_topLeftRivePosition.setY(offsetY); - // Set the model-view matrix and apply the translation and scale - m_matrix = *state->projectionMatrix(); - m_modelViewTransform = matrix4x4ToTransform(m_matrix); - // Apply transformations in the correct order - m_modelViewTransform.translate(x, y); - m_modelViewTransform.translate(offsetX, offsetY); - m_modelViewTransform.scale(scaleFactor, scaleFactor); + QTransform transformation = transform; - QPainter *painter = nullptr; + transformation.translate(bounds.x() + offsetX, bounds.y() + offsetY); + transformation.scale(scaleFactor, scaleFactor); - void *vPainter = renderInterface->getResource(m_window, QSGRendererInterface::Resource::PainterResource); - if (vPainter) { - painter = static_cast(vPainter); - } else { - return; + painter->save(); + { + painter->setTransform(transformation, false); + + m_renderer.setPainter(painter); + artboardInstance->draw(&m_renderer); } - paint(painter); -#endif - // in qt5 paint will be called by paint method of paintedItem + painter->restore(); } diff --git a/src/RiveQtQuickItem/riveqsgsoftwarerendernode.h b/src/RiveQtQuickItem/riveqsgsoftwarerendernode.h index 3fb7964..f0445c2 100644 --- a/src/RiveQtQuickItem/riveqsgsoftwarerendernode.h +++ b/src/RiveQtQuickItem/riveqsgsoftwarerendernode.h @@ -1,4 +1,3 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // @@ -6,18 +5,9 @@ #pragma once -#include -#include -#include -#include -#include - -#include - #include "riveqsgrendernode.h" #include "renderer/riveqtpainterrenderer.h" -class RiveQtQuickItem; class QQuickWindow; class RiveQSGSoftwareRenderNode : public RiveQSGRenderNode @@ -26,22 +16,12 @@ class RiveQSGSoftwareRenderNode : public RiveQSGRenderNode RiveQSGSoftwareRenderNode(QQuickWindow *window, std::weak_ptr artboardInstance, const QRectF &geometry); QRectF rect() const override; - - StateFlags changedStates() const override { return QSGRenderNode::BlendState; } - RenderingFlags flags() const override { return QSGRenderNode::BoundedRectRendering; } - + StateFlags changedStates() const override; + RenderingFlags flags() const override; void render(const RenderState *state) override; - void paint(QPainter *painter); + void paint(QPainter *painter, const QRect &bounds, const QTransform &transform = QTransform()); private: - void renderSoftware(const RenderState *state); - RiveQtPainterRenderer m_renderer; - - QPainter m_fallbackPainter; - QPixmap m_fallbackPixmap; - - QMatrix4x4 m_matrix; - QTransform m_modelViewTransform; }; diff --git a/src/RiveQtQuickItem/riveqtpath.cpp b/src/RiveQtQuickItem/riveqtpath.cpp index 6022a67..4decb8a 100644 --- a/src/RiveQtQuickItem/riveqtpath.cpp +++ b/src/RiveQtQuickItem/riveqtpath.cpp @@ -4,69 +4,46 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -#include +#include "riveqtpath.h" +#include "rqqplogging.h" +#include "riveqtutils.h" #include #include #include - #include -#include "rqqplogging.h" -#include "riveqtpath.h" -#include "riveqtutils.h" +#if !defined(USE_QPAINTERPATH_STROKER) +#include +#endif RiveQtPath::RiveQtPath() + : rive::RenderPath() { - m_qPainterPath.setFillRule(Qt::FillRule::WindingFill); - m_pathSegmentOutlineDataDirty = true; - m_pathSegmentDataDirty = true; + m_path.setFillRule(Qt::FillRule::WindingFill); } RiveQtPath::RiveQtPath(const RiveQtPath &other) -{ - m_qPainterPath = other.m_qPainterPath; - m_pathVertices = other.m_pathVertices; - + : rive::RenderPath() #if !defined(USE_QPAINTERPATH_STROKER) - m_pathSegmentsOutlineData = other.m_pathSegmentsOutlineData; - m_segmentCount = other.m_segmentCount; + , m_pathSegmentsOutlineData(other.m_pathSegmentsOutlineData) + , m_segmentCount(other.m_segmentCount) #endif - - m_pathOutlineVertices = other.m_pathOutlineVertices; - m_lod = other.m_lod; + , m_path(other.m_path) + , m_pathVertices(other.m_pathVertices) + , m_pathOutlineVertices(other.m_pathOutlineVertices) + , m_renderQuality(other.m_renderQuality) +{ } -RiveQtPath::RiveQtPath(const rive::RawPath &rawPath, rive::FillRule fillRule) +RiveQtPath::RiveQtPath(const rive::RawPath &rawPath, rive::FillRule fillRule, RiveRenderSettings::RenderQuality renderQuality) + : rive::RenderPath() + , m_renderQuality(renderQuality) { - m_qPainterPath.clear(); - m_qPainterPath.setFillRule(RiveQtUtils::riveFillRuleToQt(fillRule)); + m_path.clear(); + m_path.setFillRule(RiveQtUtils::convert(fillRule)); - for (const auto &[verb, pts] : rawPath) { - switch (verb) { - case rive::PathVerb::move: - m_qPainterPath.moveTo(pts->x, pts->y); - break; - case rive::PathVerb::line: - m_qPainterPath.lineTo(pts->x, pts->y); - break; - case rive::PathVerb::quad: - m_qPainterPath.quadTo(pts[0].x, pts[0].y, pts[1].x, pts[1].y); - break; - case rive::PathVerb::cubic: - m_qPainterPath.cubicTo(pts[0].x, pts[0].y, pts[1].x, pts[1].y, pts[2].x, pts[2].y); - break; - case rive::PathVerb::close: - m_qPainterPath.lineTo(pts->x, pts->y); - m_qPainterPath.closeSubpath(); - break; - default: - qCDebug(rqqpRendering) << "Unhandled case in RiveQtPath Constructor" << static_cast(verb); - break; - } - } - m_pathSegmentOutlineDataDirty = true; - m_pathSegmentDataDirty = true; + addRawPathImpl(rawPath); } void RiveQtPath::rewind() @@ -77,19 +54,40 @@ void RiveQtPath::rewind() m_pathSegmentsOutlineData.clear(); #endif - m_qPainterPath.clear(); + m_path.clear(); m_pathSegmentOutlineDataDirty = true; m_pathSegmentDataDirty = true; } +void RiveQtPath::moveTo(float x, float y) +{ + m_path.moveTo(x, y); +} + +void RiveQtPath::lineTo(float x, float y) +{ + m_path.lineTo(x, y); +} + +void RiveQtPath::cubicTo(float ox, float oy, float ix, float iy, float x, float y) +{ + m_path.cubicTo(ox, oy, ix, iy, x, y); +} + +void RiveQtPath::close() +{ + m_path.closeSubpath(); +} + void RiveQtPath::fillRule(rive::FillRule value) { switch (value) { case rive::FillRule::evenOdd: - m_qPainterPath.setFillRule(Qt::FillRule::OddEvenFill); + m_path.setFillRule(Qt::FillRule::OddEvenFill); break; case rive::FillRule::nonZero: - m_qPainterPath.setFillRule(Qt::FillRule::WindingFill); + default: + m_path.setFillRule(Qt::FillRule::WindingFill); break; } } @@ -106,30 +104,23 @@ void RiveQtPath::addRenderPath(rive::RenderPath *path, const rive::Mat2D &transf QTransform qTransform(transform[0], transform[1], transform[2], transform[3], transform[4], transform[5]); QPainterPath qPath = qtPath->toQPainterPath() * qTransform; - m_qPainterPath.addPath(qPath); + m_path.addPath(qPath); m_pathSegmentOutlineDataDirty = true; m_pathSegmentDataDirty = true; } -void RiveQtPath::setQPainterPath(QPainterPath path) +void RiveQtPath::addRawPath(const rive::RawPath &path) { - m_qPainterPath = path; -} + addRawPathImpl(path); -void RiveQtPath::applyMatrix(QMatrix4x4 m) -{ - m_qPainterPath = m_qPainterPath * m.toTransform(); + m_pathSegmentOutlineDataDirty = true; + m_pathSegmentDataDirty = true; } -void RiveQtPath::setLevelOfDetail(const unsigned lod) +void RiveQtPath::applyMatrix(const QMatrix4x4 &matrix) { - if (lod == 0u) { - qCDebug(rqqpRendering) << "Level of detail cannot be 0. Using 1 instead."; - m_lod = 1u; - } else { - m_lod = lod; - } + m_path = m_path * matrix.toTransform(); } QVector> RiveQtPath::toVertices() @@ -140,23 +131,33 @@ QVector> RiveQtPath::toVertices() return m_pathVertices; } +void RiveQtPath::setQPainterPath(const QPainterPath &path) +{ + m_path = path; +} + bool RiveQtPath::intersectWith(const QPainterPath &other) { - if (!m_qPainterPath.isEmpty() && !other.isEmpty()) { - if (other.intersects(m_qPainterPath)) { - QPainterPath tempQPainterPath = other.intersected(m_qPainterPath); + if (!m_path.isEmpty() && !other.isEmpty()) { + if (other.intersects(m_path)) { + QPainterPath tempQPainterPath = other.intersected(m_path); if (!tempQPainterPath.isEmpty()) { - m_qPainterPath = tempQPainterPath; + m_path = tempQPainterPath; m_pathSegmentDataDirty = true; m_pathSegmentOutlineDataDirty = true; return true; } } } - m_qPainterPath = other; + m_path = other; return false; } +QPainterPath RiveQtPath::toQPainterPath() const +{ + return m_path; +} + QVector> RiveQtPath::toVerticesLine(const QPen &pen) { if (!m_pathSegmentOutlineDataDirty) { @@ -225,23 +226,23 @@ void RiveQtPath::updatePathSegmentsOutlineData() { m_pathSegmentsOutlineData.clear(); - if (m_qPainterPath.isEmpty()) { + if (m_path.isEmpty()) { m_pathSegmentOutlineDataDirty = false; return; } QVector pathDataEnhanced; - pathDataEnhanced.reserve(m_qPainterPath.elementCount()); + pathDataEnhanced.reserve(m_path.elementCount()); - const QPointF &point = m_qPainterPath.elementAt(0); + const QPointF &point = m_path.elementAt(0); const QVector2D ¢erPoint = QVector2D(point.x(), point.y()); int currentStepIndex { 0 }; // Add the current point pathDataEnhanced.append({ centerPoint, QVector2D(), currentStepIndex }); - for (int i = 1; i < m_qPainterPath.elementCount(); ++i) { - QPainterPath::Element element = m_qPainterPath.elementAt(i); + for (int i = 1; i < m_path.elementCount(); ++i) { + QPainterPath::Element element = m_path.elementAt(i); switch (element.type) { case QPainterPath::MoveToElement: @@ -261,8 +262,8 @@ void RiveQtPath::updatePathSegmentsOutlineData() case QPainterPath::CurveToElement: { const QPointF &startPoint = pathDataEnhanced.last().point.toPointF(); const QPointF &controlPoint1 = element; - const QPointF &controlPoint2 = m_qPainterPath.elementAt(i + 1); - const QPointF &endPoint = m_qPainterPath.elementAt(i + 2); + const QPointF &controlPoint2 = m_path.elementAt(i + 1); + const QPointF &endPoint = m_path.elementAt(i + 2); pathDataEnhanced.last().tangent = cubicBezierTangent(startPoint, controlPoint1, controlPoint2, endPoint, 0.f); @@ -295,8 +296,8 @@ void RiveQtPath::updatePathOutlineVertices(const QPen &pen) m_pathOutlineVertices.clear(); QPainterPathStroker painterPathStroker(pen); painterPathStroker.setCurveThreshold(0.1); - QPainterPath strokedPath = painterPathStroker.createStroke(m_qPainterPath); - QTriangleSet triangles = qTriangulate(strokedPath, QTransform(), m_lod); + QPainterPath strokedPath = painterPathStroker.createStroke(m_path); + QTriangleSet triangles = qTriangulate(strokedPath, QTransform(), static_cast(m_renderQuality)); QVector pathData; pathData.reserve(triangles.indices.size()); @@ -518,16 +519,41 @@ void RiveQtPath::updatePathOutlineVertices(const QPen &pen) #endif } +void RiveQtPath::addRawPathImpl(const rive::RawPath &path) +{ + for (const auto &[verb, pts] : path) { + switch (verb) { + case rive::PathVerb::move: + m_path.moveTo(pts[0].x, pts[0].y); + break; + case rive::PathVerb::line: + m_path.lineTo(pts[1].x, pts[1].y); + break; + case rive::PathVerb::quad: + m_path.quadTo(pts[1].x, pts[1].y, pts[2].x, pts[2].y); + break; + case rive::PathVerb::cubic: + m_path.cubicTo(pts[1].x, pts[1].y, pts[2].x, pts[2].y, pts[3].x, pts[3].y); + break; + case rive::PathVerb::close: + // why was this done? + // m_path.lineTo(pts->x, pts->y); + m_path.closeSubpath(); + break; + } + } +} + void RiveQtPath::updatePathSegmentsData() { m_pathVertices.clear(); - if (m_qPainterPath.isEmpty()) { + if (m_path.isEmpty()) { m_pathSegmentDataDirty = false; return; } - QTriangleSet triangles = qTriangulate(m_qPainterPath, QTransform(), m_lod); + QTriangleSet triangles = qTriangulate(m_path, QTransform(), m_renderQuality); QVector pathData; pathData.reserve(triangles.indices.size()); diff --git a/src/RiveQtQuickItem/riveqtpath.h b/src/RiveQtQuickItem/riveqtpath.h index b9d3d18..faa743f 100644 --- a/src/RiveQtQuickItem/riveqtpath.h +++ b/src/RiveQtQuickItem/riveqtpath.h @@ -7,39 +7,41 @@ #define USE_QPAINTERPATH_STROKER +#include +#include + #include #include +#include #include -#include -#include +#include "datatypes.h" class RiveQtPath : public rive::RenderPath { public: RiveQtPath(); RiveQtPath(const RiveQtPath &other); - RiveQtPath(const rive::RawPath &rawPath, rive::FillRule fillRule); + RiveQtPath(const rive::RawPath &rawPath, rive::FillRule fillRule, RiveRenderSettings::RenderQuality renderQuality); void rewind() override; - void moveTo(float x, float y) override { m_qPainterPath.moveTo(x, y); } - void lineTo(float x, float y) override { m_qPainterPath.lineTo(x, y); } - void cubicTo(float ox, float oy, float ix, float iy, float x, float y) override { m_qPainterPath.cubicTo(ox, oy, ix, iy, x, y); } - void close() override { m_qPainterPath.closeSubpath(); } + void moveTo(float x, float y) override; + void lineTo(float x, float y) override; + void cubicTo(float ox, float oy, float ix, float iy, float x, float y) override; + void close() override; void fillRule(rive::FillRule value) override; void addRenderPath(rive::RenderPath *path, const rive::Mat2D &transform) override; + void addRawPath(const rive::RawPath &path) override; - void setQPainterPath(QPainterPath path); + void setQPainterPath(const QPainterPath &path); bool intersectWith(const QPainterPath &other); - QPainterPath toQPainterPath() { return m_qPainterPath; } - QPainterPath toQPainterPaths(const QMatrix4x4 &t); - - void setLevelOfDetail(const unsigned lod); + QPainterPath toQPainterPath() const; QVector> toVertices(); QVector> toVerticesLine(const QPen &pen); - void applyMatrix(QMatrix4x4 m); + void applyMatrix(const QMatrix4x4 &matrix); + private: #if !defined(USE_QPAINTERPATH_STROKER) struct PathDataPoint @@ -60,12 +62,14 @@ class RiveQtPath : public rive::RenderPath void updatePathSegmentsData(); void updatePathOutlineVertices(const QPen &pen); - QPainterPath m_qPainterPath; + void addRawPathImpl(const rive::RawPath &path); + + QPainterPath m_path; QVector> m_pathVertices; QVector> m_pathOutlineVertices; bool m_pathSegmentDataDirty { true }; bool m_pathSegmentOutlineDataDirty { true }; - unsigned m_lod { 1 }; + RiveRenderSettings::RenderQuality m_renderQuality { RiveRenderSettings::RenderQuality::Medium }; }; diff --git a/src/RiveQtQuickItem/riveqtquickitem.cpp b/src/RiveQtQuickItem/riveqtquickitem.cpp index fb55be5..e3d1329 100644 --- a/src/RiveQtQuickItem/riveqtquickitem.cpp +++ b/src/RiveQtQuickItem/riveqtquickitem.cpp @@ -1,41 +1,25 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // // SPDX-License-Identifier: LGPL-3.0-or-later +#include "riveqtquickitem.h" +#include "riveqsgrendernode.h" +#include "rqqplogging.h" +#include "riveqsgsoftwarerendernode.h" +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#include "riveqsgrhirendernode.h" +#endif + #include -#include #include #include #include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include "rive/animation/state_machine_input_instance.hpp" -#include "rqqplogging.h" -#include "riveqtquickitem.h" -#include "renderer/riveqtfactory.h" - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -# include "riveqsgsoftwarerendernode.h" -#endif - RiveQtQuickItem::RiveQtQuickItem(QQuickItem *parent) -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - : QQuickPaintedItem(parent) -#else - : QQuickItem(parent) -#endif + : RiveQtQuickItemBase(parent) { // set global flags and configs of our item // TODO: maybe we should also allow Hover Events to be used @@ -99,7 +83,7 @@ void RiveQtQuickItem::triggerAnimation(int id) m_currentAnimationIndex = id; m_animationInstance = m_currentArtboardInstance->animationAt(id); - qCDebug(rqqpItem) << "Selected Animation" << QString::fromStdString(m_animationInstance->name()); + qCDebug(rqqpItem) << "Selected animation" << QString::fromStdString(m_animationInstance->name()); emit currentAnimationIndexChanged(); } @@ -232,7 +216,7 @@ QSGNode *RiveQtQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData } if (!m_currentArtboardInstance) { - qCDebug(rqqpItem) << "No artboard loaded."; + qCDebug(rqqpItem) << "No artboard loaded"; m_currentStateMachineInstance = nullptr; if (m_stateMachineInterface) { m_stateMachineInterface->setStateMachineInstance(m_currentStateMachineInstance.get()); @@ -271,7 +255,7 @@ QSGNode *RiveQtQuickItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData } if (!m_renderNode && m_currentArtboardInstance) { - m_renderNode = m_riveQtFactory.renderNode(currentWindow, m_currentArtboardInstance, this->boundingRect()); + m_renderNode = createRenderNode(m_renderSettings, currentWindow, m_currentArtboardInstance, this->boundingRect()); } qint64 currentTime = m_elapsedTimer.elapsed(); @@ -487,7 +471,7 @@ void RiveQtQuickItem::loadRiveFile(const QString &source) QFile file(source); if (!file.open(QIODevice::ReadOnly)) { - qCWarning(rqqpItem) << "Failed to open the file " << source; + qCWarning(rqqpItem) << "Failed to open the file:" << source; m_loadingStatus = Error; emit loadingStatusChanged(); return; @@ -502,14 +486,13 @@ void RiveQtQuickItem::loadRiveFile(const QString &source) m_riveFile = rive::File::import(dataSpan, &m_riveQtFactory, &importResult); if (importResult != rive::ImportResult::success) { - qCDebug(rqqpItem) << "Failed to import Rive file."; + qCDebug(rqqpItem) << "Failed to import Rive file"; m_loadingStatus = Error; emit loadingStatusChanged(); return; } m_renderSettings.graphicsApi = currentWindow->rendererInterface()->graphicsApi(); - m_riveQtFactory.setRenderSettings(m_renderSettings); // Update artboard info m_artboardInfoList.clear(); @@ -520,7 +503,7 @@ void RiveQtQuickItem::loadRiveFile(const QString &source) ArtBoardInfo info; info.id = i; info.name = QString::fromStdString(m_riveFile->artboardNameAt(i)); - qCDebug(rqqpInspection) << "ArtBoardInfo" << i << "found.\tName:" << info.name; + qCDebug(rqqpInspection) << "ArtBoardInfo" << i << "found with name:" << info.name; m_artboardInfoList.append(info); } @@ -538,7 +521,7 @@ void RiveQtQuickItem::loadRiveFile(const QString &source) emit stateMachineInterfaceChanged(); } - qCDebug(rqqpItem) << "Successfully imported Rive file."; + qCDebug(rqqpItem) << "Successfully imported Rive file"; m_loadingStatus = Loaded; m_loadingGuard = false; emit loadingStatusChanged(); @@ -565,8 +548,8 @@ void RiveQtQuickItem::updateAnimations() info.duration = animation->duration(); info.fps = animation->fps(); - qCDebug(rqqpInspection) << "Animation" << i << "found.\tDuration:" << animation->duration() << "\tFPS:" << animation->fps() - << "\tName:" << info.name; + qCDebug(rqqpInspection) << "Animation" << i << "found, duration:" << animation->duration() << "fps:" << animation->fps() + << "name:" << info.name; m_animationList.append(info); } @@ -589,7 +572,7 @@ void RiveQtQuickItem::updateStateMachines() info.id = i; info.name = QString::fromStdString(stateMachine->name()); - qCDebug(rqqpInspection) << "StateMachineInfo" << i << "found.\tName:" << info.name; + qCDebug(rqqpInspection) << "State machine" << i << "found, name:" << info.name; m_stateMachineList.append(info); } @@ -597,7 +580,6 @@ void RiveQtQuickItem::updateStateMachines() emit stateMachinesChanged(); } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) void RiveQtQuickItem::renderOffscreen() { // its okay io call this since we are sure that the renderthread is not active when we get called @@ -611,13 +593,10 @@ void RiveQtQuickItem::renderOffscreen() m_renderNode->renderOffscreen(); } } -#endif bool RiveQtQuickItem::hitTest(const QPointF &pos, const rive::ListenerType &type) { if (!m_riveFile || !m_currentArtboardInstance || !m_currentStateMachineInstance) { - // qCDebug(rqqpItem) << Q_FUNC_INFO << "File, Artboard, StateMachine is null:" << (m_riveFile == nullptr) - // << (m_currentArtboardInstance == nullptr) << (m_currentStateMachineInstance == nullptr); return false; } @@ -639,6 +618,9 @@ bool RiveQtQuickItem::hitTest(const QPointF &pos, const rive::ListenerType &type case rive::ListenerType::up: m_currentStateMachineInstance->pointerUp(rive::Vec2D(m_lastMouseX, m_lastMouseY)); return true; + case rive::ListenerType::click: + case rive::ListenerType::draggableConstraint: + case rive::ListenerType::event: case rive::ListenerType::enter: case rive::ListenerType::exit: // not handled in rivecpp as well @@ -648,6 +630,25 @@ bool RiveQtQuickItem::hitTest(const QPointF &pos, const rive::ListenerType &type return false; } +RiveQSGRenderNode *RiveQtQuickItem::createRenderNode(const RiveRenderSettings &renderSettings, + QQuickWindow *window, + std::weak_ptr artboardInstance, + const QRectF &geometry) +{ + switch (renderSettings.graphicsApi) { +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + case QSGRendererInterface::GraphicsApi::OpenGLRhi: + case QSGRendererInterface::GraphicsApi::MetalRhi: + case QSGRendererInterface::GraphicsApi::VulkanRhi: + case QSGRendererInterface::GraphicsApi::Direct3D11Rhi: + return RiveQSGRHIRenderNode::create(renderSettings, window, artboardInstance, geometry); +#endif + case QSGRendererInterface::GraphicsApi::Software: + default: + return new RiveQSGSoftwareRenderNode(window, artboardInstance, geometry); + } +} + const QVector &RiveQtQuickItem::animations() const { return m_animationList; @@ -670,7 +671,6 @@ int RiveQtQuickItem::currentArtboardIndex() const void RiveQtQuickItem::updateCurrentStateMachineIndex() { - qCDebug(rqqpItem) << Q_FUNC_INFO; if (!m_currentArtboardInstance) { qCDebug(rqqpItem) << "Cannot update state machine index"; return; @@ -721,8 +721,6 @@ QRectF RiveQtQuickItem::artboardRect() void RiveQtQuickItem::updateCurrentArtboardIndex() { - qCDebug(rqqpItem) << Q_FUNC_INFO; - if (!m_riveFile) { return; } @@ -752,17 +750,17 @@ void RiveQtQuickItem::updateCurrentArtboardIndex() setCurrentArtboardIndex(info->id); } -void RiveQtQuickItem::setCurrentArtboardIndex(const int newIndex) +void RiveQtQuickItem::setCurrentArtboardIndex(int index) { if (!m_riveFile) { - qCDebug(rqqpItem) << "Setting initial artboard index to" << newIndex; - m_initialArtboardIndex = newIndex; + qCDebug(rqqpItem) << "Setting initial artboard index to" << index; + m_initialArtboardIndex = index; m_scheduleArtboardChange = true; return; } - if (newIndex < 0 || newIndex >= m_riveFile->artboardCount()) { - qCWarning(rqqpItem) << "Cannot select artboard. Index" << newIndex << "out of bounds [0, " << m_riveFile->artboardCount() << "["; + if (index < 0 || index >= m_riveFile->artboardCount()) { + qCWarning(rqqpItem) << "Cannot select artboard. Index" << index << "out of bounds [0, " << m_riveFile->artboardCount() << "["; qCDebug(rqqpItem) << "Trying to set default artboard index"; const auto defaultArtboard = m_riveFile->artboardDefault(); if (!defaultArtboard) { @@ -787,12 +785,12 @@ void RiveQtQuickItem::setCurrentArtboardIndex(const int newIndex) return; } - if (m_currentArtboardIndex == newIndex) { + if (m_currentArtboardIndex == index) { return; } - qCDebug(rqqpItem) << "Setting current artboard index to" << newIndex; - m_currentArtboardIndex = newIndex; + qCDebug(rqqpItem) << "Setting current artboard index:" << index; + m_currentArtboardIndex = index; emit currentArtboardIndexChanged(); m_scheduleArtboardChange = true; // we have to do this in the render thread. @@ -805,15 +803,14 @@ int RiveQtQuickItem::currentStateMachineIndex() const return m_currentStateMachineIndex; } -void RiveQtQuickItem::setCurrentStateMachineIndex(const int newCurrentStateMachineIndex) +void RiveQtQuickItem::setCurrentStateMachineIndex(int index) { - qCDebug(rqqpItem) << Q_FUNC_INFO << newCurrentStateMachineIndex; - if (m_currentStateMachineIndex == newCurrentStateMachineIndex) { + if (m_currentStateMachineIndex == index) { return; } if (!m_riveFile) { - m_initialStateMachineIndex = newCurrentStateMachineIndex; // file not yet loaded, save the info from qml + m_initialStateMachineIndex = index; // file not yet loaded, save the info from qml return; } @@ -821,8 +818,10 @@ void RiveQtQuickItem::setCurrentStateMachineIndex(const int newCurrentStateMachi return; } + qCDebug(rqqpItem) << "Setting current state machine index:" << index; + // -1 is a valid value! - m_currentStateMachineIndex = newCurrentStateMachineIndex; + m_currentStateMachineIndex = index; emit currentStateMachineIndexChanged(); m_scheduleStateMachineChange = true; // we have to do this in the render thread. @@ -856,17 +855,17 @@ bool RiveQtQuickItem::interactive() const return acceptedMouseButtons() == Qt::AllButtons; } -void RiveQtQuickItem::setInteractive(bool newInteractive) +void RiveQtQuickItem::setInteractive(bool interactive) { - if ((acceptedMouseButtons() == Qt::AllButtons && newInteractive) || (acceptedMouseButtons() != Qt::AllButtons && !newInteractive)) { + if ((acceptedMouseButtons() == Qt::AllButtons && interactive) || (acceptedMouseButtons() != Qt::AllButtons && !interactive)) { return; } - if (newInteractive) { + if (interactive) { setAcceptedMouseButtons(Qt::AllButtons); } - if (!newInteractive) { + if (!interactive) { setAcceptedMouseButtons(Qt::NoButton); } @@ -878,7 +877,7 @@ RiveRenderSettings::PostprocessingMode RiveQtQuickItem::postprocessingMode() con return m_renderSettings.postprocessingMode; } -void RiveQtQuickItem::setPostprocessingMode(const RiveRenderSettings::PostprocessingMode mode) +void RiveQtQuickItem::setPostprocessingMode(RiveRenderSettings::PostprocessingMode mode) { m_renderSettings.postprocessingMode = mode; emit postprocessingModeChanged(); @@ -889,7 +888,7 @@ RiveRenderSettings::RenderQuality RiveQtQuickItem::renderQuality() const return m_renderSettings.renderQuality; } -void RiveQtQuickItem::setRenderQuality(const RiveRenderSettings::RenderQuality quality) +void RiveQtQuickItem::setRenderQuality(RiveRenderSettings::RenderQuality quality) { m_renderSettings.renderQuality = quality; emit renderQualityChanged(); @@ -900,7 +899,7 @@ RiveRenderSettings::FillMode RiveQtQuickItem::fillMode() const return m_renderSettings.fillMode; } -void RiveQtQuickItem::setFillMode(const RiveRenderSettings::FillMode fillMode) +void RiveQtQuickItem::setFillMode(RiveRenderSettings::FillMode fillMode) { m_renderSettings.fillMode = fillMode; emit fillModeChanged(); @@ -915,7 +914,7 @@ int RiveQtQuickItem::frameRate() void RiveQtQuickItem::paint(QPainter *painter) { if (m_renderNode) { - static_cast(m_renderNode)->paint(painter); + static_cast(m_renderNode)->paint(painter, { 0, 0, painter->device()->width(), painter->device()->height() }); } } #endif diff --git a/src/RiveQtQuickItem/riveqtquickitem.h b/src/RiveQtQuickItem/riveqtquickitem.h index 0dd93ff..8c740ec 100644 --- a/src/RiveQtQuickItem/riveqtquickitem.h +++ b/src/RiveQtQuickItem/riveqtquickitem.h @@ -5,23 +5,26 @@ #pragma once -#include #include -#include #include #include -#include -#include -#include -#include - -#include -#include +#include +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +#include +#define RiveQtQuickItemBase QQuickPaintedItem +#else +#define RiveQtQuickItemBase QQuickItem +#endif #include "rivestatemachineinput.h" #include "datatypes.h" #include "renderer/riveqtfactory.h" +#include +#include +#include +#include + #if defined(RIVEQTQUICKITEM_LIBRARY) # define RIVEQTQUICKITEM_EXPORT Q_DECL_EXPORT #else @@ -29,11 +32,6 @@ #endif class RiveQSGRenderNode; -class RiveQSGRHIRenderNode; - -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -class RiveQSGSoftwareRenderNode; -#endif /** * \class RiveQtQuickItem * \brief A quick item for Rive-based animations. @@ -42,11 +40,7 @@ class RiveQSGSoftwareRenderNode; * \author Jeremias Bosch, Jonas Kalinka, basysKom GmbH * \date 2023/08/01 */ -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) -class RiveQtQuickItem : public QQuickPaintedItem -#else -class RiveQtQuickItem : public QQuickItem -#endif +class RiveQtQuickItem : public RiveQtQuickItemBase { Q_OBJECT @@ -390,29 +384,29 @@ class RiveQtQuickItem : public QQuickItem int currentAnimationIndex() const; int currentArtboardIndex() const; - void setCurrentArtboardIndex(const int newCurrentArtboardIndex); + void setCurrentArtboardIndex(int index); const QVector &artboards() const; const QVector &stateMachines() const; const QVector &animations() const; int currentStateMachineIndex() const; - void setCurrentStateMachineIndex(const int newCurrentStateMachineIndex); + void setCurrentStateMachineIndex(int index); RiveStateMachineInput *stateMachineInterface() const; void setStateMachineInterface(RiveStateMachineInput *stateMachineInterface); bool interactive() const; - void setInteractive(bool newInteractive); + void setInteractive(bool interactive); RiveRenderSettings::PostprocessingMode postprocessingMode() const; - void setPostprocessingMode(const RiveRenderSettings::PostprocessingMode mode); + void setPostprocessingMode(RiveRenderSettings::PostprocessingMode mode); RiveRenderSettings::RenderQuality renderQuality() const; - void setRenderQuality(const RiveRenderSettings::RenderQuality quality); + void setRenderQuality(RiveRenderSettings::RenderQuality quality); RiveRenderSettings::FillMode fillMode() const; - void setFillMode(const RiveRenderSettings::FillMode fillMode); + void setFillMode(RiveRenderSettings::FillMode fillMode); int frameRate(); @@ -458,7 +452,6 @@ class RiveQtQuickItem : public QQuickItem void mousePressEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; - void hoverMoveEvent(QHoverEvent *event) override; void hoverEnterEvent(QHoverEvent *event) override; void hoverLeaveEvent(QHoverEvent *event) override; @@ -471,15 +464,19 @@ class RiveQtQuickItem : public QQuickItem void updateStateMachines(); void updateCurrentArtboardIndex(); void updateCurrentStateMachineIndex(); + void updateStateMachineValues(); QRectF artboardRect(); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) void renderOffscreen(); -#endif bool hitTest(const QPointF &pos, const rive::ListenerType &type); + RiveQSGRenderNode *createRenderNode(const RiveRenderSettings &renderSettings, + QQuickWindow *window, + std::weak_ptr artboardInstance, + const QRectF &geometry); + QVector m_artboardInfoList; QVector m_animationList; QVector m_stateMachineList; @@ -521,10 +518,6 @@ class RiveQtQuickItem : public QQuickItem int m_frameRate { 0 }; RiveQSGRenderNode *m_renderNode { nullptr }; - void updateStateMachineValues(); bool m_loadingGuard { false }; -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - RiveQSGSoftwareRenderNode *softwareRenderNode; -#endif }; diff --git a/src/RiveQtQuickItem/riveqtquickplugin.cpp b/src/RiveQtQuickItem/riveqtquickplugin.cpp index 7550286..0fc84bd 100644 --- a/src/RiveQtQuickItem/riveqtquickplugin.cpp +++ b/src/RiveQtQuickItem/riveqtquickplugin.cpp @@ -1,4 +1,3 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // diff --git a/src/RiveQtQuickItem/riveqtquickplugin.h b/src/RiveQtQuickItem/riveqtquickplugin.h index 85910f8..aec52d6 100644 --- a/src/RiveQtQuickItem/riveqtquickplugin.h +++ b/src/RiveQtQuickItem/riveqtquickplugin.h @@ -1,4 +1,3 @@ - // SPDX-FileCopyrightText: 2023 Jeremias Bosch // SPDX-FileCopyrightText: 2023 basysKom GmbH // diff --git a/src/RiveQtQuickItem/rivestatemachineinput.cpp b/src/RiveQtQuickItem/rivestatemachineinput.cpp index e2185d1..63ca5e0 100644 --- a/src/RiveQtQuickItem/rivestatemachineinput.cpp +++ b/src/RiveQtQuickItem/rivestatemachineinput.cpp @@ -3,20 +3,35 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later -#include -#include -#include +#include "rivestatemachineinput.h" +#include "rqqplogging.h" +#include #include +#include #include #include #include #include #include -#include "rivestatemachineinput.h" -#include "rqqplogging.h" +namespace { + // we ignore properties with those names as they will + // conflict with JS/QML environment + const QStringList reservedWords = { "await", "break", "case", "catch", + "class", "const", "continue", "debugger", + "default", "delete", "do", "else", + "export", "extends", "finally", "for", + "function", "if", "import", "in", + "instanceof", "new", "return", "super", + "switch", "this", "throw", "try", + "typeof", "var", "void", "while", + "with", "yield", "enum", "implements", + "interface", "let", "package", "private", + "protected", "public", "static", "riveQtArtboardName", + "riveInputs" }; +} RiveStateMachineInput::RiveStateMachineInput(QObject *parent) : QObject(parent) diff --git a/src/RiveQtQuickItem/rivestatemachineinput.h b/src/RiveQtQuickItem/rivestatemachineinput.h index 72b851e..42b2cc9 100644 --- a/src/RiveQtQuickItem/rivestatemachineinput.h +++ b/src/RiveQtQuickItem/rivestatemachineinput.h @@ -2,16 +2,18 @@ // SPDX-FileCopyrightText: 2023 basysKom GmbH // // SPDX-License-Identifier: LGPL-3.0-or-later -#pragma once -#include "qqmlcontext.h" -#include +#pragma once -#include -#include +#include +#include +#include +#include #if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) -# include +#include +#else +#include #endif /** @@ -122,7 +124,6 @@ class DynamicPropertyHolder : public QObject private: QVariant m_value; - QJSValue m_toString; public: @@ -145,15 +146,18 @@ class DynamicPropertyHolder : public QObject void valueChanged(); }; -class QQmlEngine; +namespace rive { + class StateMachineInstance; + class SMIInput; +} + class RiveStateMachineInput : public QObject, public QQmlParserStatus { Q_OBJECT + Q_PROPERTY(QVariantList riveInputs READ riveInputs NOTIFY riveInputsChanged) Q_INTERFACES(QQmlParserStatus) - QML_NAMED_ELEMENT(RiveStateMachineInput) - Q_PROPERTY(QVariantList riveInputs READ riveInputs NOTIFY riveInputsChanged) public: enum class RivePropertyType : short { @@ -196,22 +200,9 @@ private slots: private: QString cleanUpRiveName(const QString &name); - - // we ignore properties with those names as they will - // conflict with JS/QML environment - const QStringList reservedWords = { "await", "break", "case", "catch", - "class", "const", "continue", "debugger", - "default", "delete", "do", "else", - "export", "extends", "finally", "for", - "function", "if", "import", "in", - "instanceof", "new", "return", "super", - "switch", "this", "throw", "try", - "typeof", "var", "void", "while", - "with", "yield", "enum", "implements", - "interface", "let", "package", "private", - "protected", "public", "static", "riveQtArtboardName", - "riveInputs" }; void connectStateMachineToProperties(); + QPair updateProperty(const QString &propertyName, const QVariant &propertyValue); + rive::StateMachineInstance *m_stateMachineInstance { nullptr }; QMap m_inputMap; @@ -221,8 +212,6 @@ private slots: QVariantMap m_generatedRivePropertyMap; QMap m_dynamicProperties; - - QPair updateProperty(const QString &propertyName, const QVariant &propertyValue); }; Q_DECLARE_METATYPE(RiveStateMachineInput::RivePropertyType)