diff options
| author | Laszlo Agocs <laszlo.agocs@qt.io> | 2023-05-30 11:52:37 +0200 |
|---|---|---|
| committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2023-06-01 11:27:56 +0200 |
| commit | b62efbe1afbec0eada19eeb66e55f68e2d129e36 (patch) | |
| tree | 46c8b686ab7c5fd249d19a8574439d3d84b9713a /examples/quick | |
| parent | 6bdc58c2dbeffe723e4d6ae878ad380e118104ca (diff) | |
Add the rhitextureitem example
fboitem, the OpenGL-based QQuickFramebufferObject example is now gone,
replaced by the rhitextureitem example.
It is now possible to implement a custom QQuickItem that renders into a
QRhiTexture and then draws a triangle/strip geometry textured with that
texture using just public Qt Quick APIs and the semi-public QRhi APIs.
There should be conveniences provided for this in future Qt versions,
but for the time being we provide an example how applications can do
this in Qt 6.6 already. This complements the rhiunderqml example which
shows the underlay/overlay approach, and the customrendernode example
that shows the "inline" approach with a custom QSGRenderNode. The
rhitextureitem example added here shows the third, "offscreen" approach
that goes through a texture.
The example docs are better than before but not yet complete.
To be extended separately.
Task-number: QTBUG-113331
Change-Id: I83000c08b057dd72371e2909905120dc496cb34d
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'examples/quick')
27 files changed, 791 insertions, 425 deletions
diff --git a/examples/quick/scenegraph/CMakeLists.txt b/examples/quick/scenegraph/CMakeLists.txt index 74b35f9086..156b1ed186 100644 --- a/examples/quick/scenegraph/CMakeLists.txt +++ b/examples/quick/scenegraph/CMakeLists.txt @@ -8,8 +8,8 @@ qt_internal_add_example(threadedanimation) qt_internal_add_example(twotextureproviders) qt_internal_add_example(customrendernode) qt_internal_add_example(rhiunderqml) +qt_internal_add_example(rhitextureitem) if(QT_FEATURE_opengl OR QT_FEATURE_opengles2 OR QT_FEATURE_opengles3) - qt_internal_add_example(fboitem) qt_internal_add_example(openglunderqml) endif() if(IOS OR MACOS) diff --git a/examples/quick/scenegraph/fboitem/CMakeLists.txt b/examples/quick/scenegraph/fboitem/CMakeLists.txt deleted file mode 100644 index 371c7e31ed..0000000000 --- a/examples/quick/scenegraph/fboitem/CMakeLists.txt +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright (C) 2022 The Qt Company Ltd. -# SPDX-License-Identifier: BSD-3-Clause - -cmake_minimum_required(VERSION 3.16) -project(fboitem LANGUAGES CXX) - -if(NOT DEFINED INSTALL_EXAMPLESDIR) - set(INSTALL_EXAMPLESDIR "examples") -endif() - -set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/fboitem") - -find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick) - -qt_standard_project_setup() - -qt_add_executable(fboitem WIN32 MACOSX_BUNDLE - ../shared/logorenderer.cpp ../shared/logorenderer.h - fboinsgrenderer.cpp fboinsgrenderer.h - main.cpp -) - -target_include_directories(fboitem PUBLIC - ../shared -) - -target_link_libraries(fboitem PRIVATE - Qt6::Core - Qt6::Gui - Qt6::Qml - Qt6::Quick -) - -qt_add_qml_module(fboitem - URI SceneGraphRendering - QML_FILES main.qml - RESOURCES shaders/checker.frag.qsb - RESOURCE_PREFIX /scenegraph/fboitem - NO_RESOURCE_TARGET_PATH -) - -install(TARGETS fboitem - RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" - BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" - LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" -) diff --git a/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg b/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg Binary files differdeleted file mode 100644 index 306b8bab20..0000000000 --- a/examples/quick/scenegraph/fboitem/doc/images/fboitem-example.jpg +++ /dev/null diff --git a/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc b/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc deleted file mode 100644 index daa784bf79..0000000000 --- a/examples/quick/scenegraph/fboitem/doc/src/fboitem.qdoc +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only - -/*! - \example scenegraph/fboitem - \title Scene Graph - Rendering FBOs - \ingroup qtquickexamples - - \brief Shows how to use FramebufferObjects with Qt Quick. - - \image fboitem-example.jpg - */ diff --git a/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp b/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp deleted file mode 100644 index e4c0e61843..0000000000 --- a/examples/quick/scenegraph/fboitem/fboinsgrenderer.cpp +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include "fboinsgrenderer.h" -#include "logorenderer.h" - -#include <QOpenGLFramebufferObject> - -#include <QtQuick/QQuickWindow> -#include <qsgsimpletexturenode.h> - -class LogoInFboRenderer : public QQuickFramebufferObject::Renderer -{ -public: - LogoInFboRenderer() - { - logo.initialize(); - } - - void render() override { - logo.render(); - update(); - } - - QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) override { - QOpenGLFramebufferObjectFormat format; - format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); - format.setSamples(4); - return new QOpenGLFramebufferObject(size, format); - } - - LogoRenderer logo; -}; - -QQuickFramebufferObject::Renderer *FboInSGRenderer::createRenderer() const -{ - return new LogoInFboRenderer(); -} diff --git a/examples/quick/scenegraph/fboitem/fboinsgrenderer.h b/examples/quick/scenegraph/fboitem/fboinsgrenderer.h deleted file mode 100644 index c6eb745d5f..0000000000 --- a/examples/quick/scenegraph/fboitem/fboinsgrenderer.h +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef FBOINSGRENDERER_H -#define FBOINSGRENDERER_H - -#include <QtQuick/QQuickFramebufferObject> - -class LogoRenderer; - -class FboInSGRenderer : public QQuickFramebufferObject -{ - Q_OBJECT - QML_NAMED_ELEMENT(Renderer) -public: - Renderer *createRenderer() const; -}; - -#endif diff --git a/examples/quick/scenegraph/fboitem/fboitem.pro b/examples/quick/scenegraph/fboitem/fboitem.pro deleted file mode 100644 index 180c2288e2..0000000000 --- a/examples/quick/scenegraph/fboitem/fboitem.pro +++ /dev/null @@ -1,20 +0,0 @@ -QT += qml quick - -CONFIG += qmltypes -QML_IMPORT_NAME = SceneGraphRendering -QML_IMPORT_MAJOR_VERSION = 1 - -HEADERS += fboinsgrenderer.h -SOURCES += fboinsgrenderer.cpp main.cpp - -INCLUDEPATH += ../shared -HEADERS += ../shared/logorenderer.h -SOURCES += ../shared/logorenderer.cpp - -RESOURCES += fboitem.qrc - -target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/fboitem -INSTALLS += target - -OTHER_FILES += \ - main.qml diff --git a/examples/quick/scenegraph/fboitem/fboitem.qrc b/examples/quick/scenegraph/fboitem/fboitem.qrc deleted file mode 100644 index 1782429798..0000000000 --- a/examples/quick/scenegraph/fboitem/fboitem.qrc +++ /dev/null @@ -1,6 +0,0 @@ -<RCC> - <qresource prefix="/scenegraph/fboitem"> - <file>main.qml</file> - <file>shaders/checker.frag.qsb</file> - </qresource> -</RCC> diff --git a/examples/quick/scenegraph/fboitem/shaders/checker.frag.qsb b/examples/quick/scenegraph/fboitem/shaders/checker.frag.qsb Binary files differdeleted file mode 100644 index 77cbf0b867..0000000000 --- a/examples/quick/scenegraph/fboitem/shaders/checker.frag.qsb +++ /dev/null diff --git a/examples/quick/scenegraph/rhitextureitem/CMakeLists.txt b/examples/quick/scenegraph/rhitextureitem/CMakeLists.txt new file mode 100644 index 0000000000..d1ce25e313 --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/CMakeLists.txt @@ -0,0 +1,66 @@ +# Copyright (C) 2023 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +cmake_minimum_required(VERSION 3.16) +project(rhitextureitem LANGUAGES CXX) + +if(NOT DEFINED INSTALL_EXAMPLESDIR) + set(INSTALL_EXAMPLESDIR "examples") +endif() + +set(INSTALL_EXAMPLEDIR "${INSTALL_EXAMPLESDIR}/quick/scenegraph/rhitextureitem") + +find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick ShaderTools) + +qt_standard_project_setup() + +qt_add_executable(rhitextureitem WIN32 MACOSX_BUNDLE + rhitextureitem.cpp rhitextureitem.h + main.cpp +) + +target_include_directories(rhitextureitem PUBLIC + ../shared +) + +target_link_libraries(rhitextureitem PRIVATE + Qt6::Core + Qt6::Gui + Qt6::GuiPrivate + Qt6::Qml + Qt6::Quick + Qt6::QuickPrivate +) + +qt_add_qml_module(rhitextureitem + URI SceneGraphRendering + QML_FILES main.qml + RESOURCE_PREFIX /scenegraph/rhitextureitem + NO_RESOURCE_TARGET_PATH +) + +qt_add_shaders(rhitextureitem "rhitextureitem_shaders" + PRECOMPILE + OPTIMIZED + PREFIX + /scenegraph/rhitextureitem + FILES + shaders/logo.vert + shaders/logo.frag +) + +qt_add_shaders(rhitextureitem "rhitextureitem_effect_shaders" + BATCHABLE + PRECOMPILE + OPTIMIZED + PREFIX + /scenegraph/rhitextureitem + FILES + shaders/checker.frag +) + +install(TARGETS rhitextureitem + RUNTIME DESTINATION "${INSTALL_EXAMPLEDIR}" + BUNDLE DESTINATION "${INSTALL_EXAMPLEDIR}" + LIBRARY DESTINATION "${INSTALL_EXAMPLEDIR}" +) diff --git a/examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpg b/examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpg Binary files differnew file mode 100644 index 0000000000..4f50f94f04 --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/doc/images/rhitextureitem-example.jpg diff --git a/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc b/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc new file mode 100644 index 0000000000..97f0588314 --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/doc/src/rhitextureitem.qdoc @@ -0,0 +1,61 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only + +/*! + \example scenegraph/rhitextureitem + \title Scene Graph - RHI Texture Item + \ingroup qtquickexamples + + \brief Shows how to implement a custom QQuickItem that displays a QRhi-rendered texture. + + \image rhitextureitem-example.jpg + + This example shows how to implement an item that performs cross-platform, + portable 3D rendering into a texture using the QRhi APIs and then displays + that image. + + The \l{Scene Graph - RHI Under QML}{RHI Under QML} example shows how to + implement portable, cross-platform 3D rendering with the \l QRhi APIs in a + manner where the custom rendering is issued before the Qt Quick scene + graph's own rendering, effectively providing an "underlay". That approach + is efficient since now additional render targets and render passes are + needed, the custom rendering is injected in the main render pass before the + scene graph's own draw calls. + + In contrast, this example involves a separate render target (a QRhiTexture, + the \l{QRhiTexture::pixelSize()}{dimensions} of which match the + QQuickItem's size in the scene) and a whole render pass that is used to + clear and then draw into that texture. The texture is then used with an + instance of a custom QQuickItem subclass that is implemented using the \l + QSGSimpleTextureNode helper class. + + Compared to the underlay/overlay approach, this allows displaying, + blending, and transforming the flattened 2D image of the 3D rendering + anywhere in the Qt Quick scene since here we have a true QQuickItem. This + comes at the expense of being more expensive in terms of resources and + performance since it involves rendering to a texture first. + + \section1 Walkthrough + + \c ExampleRhiItem is the QQuickItem subclass that is exposed to QML + and is instantied in the scene. + + \snippet scenegraph/rhitextureitem/rhitextureitem.h item + + The \c angle property has a \l NumberAnimation on it, this is what drives + the continuous rotation of the 3D mesh. + + \snippet scenegraph/rhitextureitem/main.qml 0 + + \c ExampleRhiItem drives from \c RhiItem, which contains the generic + implementation of a \l QQuickItem that maintains and displays a \l + QRhiTexture. + + \snippet scenegraph/rhitextureitem/rhitextureitem.h itembase + + The corresponding scene graph node is implemented using \l + QSGSimpleTextureNode. + + \snippet scenegraph/rhitextureitem/rhitextureitem.h itemnode + + */ diff --git a/examples/quick/scenegraph/fboitem/main.cpp b/examples/quick/scenegraph/rhitextureitem/main.cpp index bbf3805002..5092552691 100644 --- a/examples/quick/scenegraph/fboitem/main.cpp +++ b/examples/quick/scenegraph/rhitextureitem/main.cpp @@ -1,21 +1,17 @@ -// Copyright (C) 2017 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause #include <QGuiApplication> - -#include <QtQuick/QQuickView> - -#include "fboinsgrenderer.h" +#include <QQuickView> +#include "rhitextureitem.h" int main(int argc, char **argv) { QGuiApplication app(argc, argv); - QQuickWindow::setGraphicsApi(QSGRendererInterface::OpenGL); - QQuickView view; view.setResizeMode(QQuickView::SizeRootObjectToView); - view.setSource(QUrl("qrc:///scenegraph/fboitem/main.qml")); + view.setSource(QUrl("qrc:///scenegraph/rhitextureitem/main.qml")); view.show(); return QGuiApplication::exec(); diff --git a/examples/quick/scenegraph/fboitem/main.qml b/examples/quick/scenegraph/rhitextureitem/main.qml index db2df19197..5a3119c87a 100644 --- a/examples/quick/scenegraph/fboitem/main.qml +++ b/examples/quick/scenegraph/rhitextureitem/main.qml @@ -1,8 +1,7 @@ -// Copyright (C) 2017 The Qt Company Ltd. +// Copyright (C) 2023 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause import QtQuick - import SceneGraphRendering Item { @@ -20,14 +19,23 @@ Item { property size pixelSize: Qt.size(width / tileSize, height / tileSize); - fragmentShader: "qrc:/scenegraph/fboitem/shaders/checker.frag.qsb" + fragmentShader: "qrc:/scenegraph/rhitextureitem/shaders/checker.frag.qsb" } - Renderer { + //! [0] + ExampleRhiItem { id: renderer anchors.fill: parent anchors.margins: 10 + NumberAnimation on angle { + from: 0 + to: 360 + duration: 5000 + loops: Animation.Infinite + } + //! [0] + // The transform is just to show something interesting.. transform: [ Rotation { id: rotation; axis.x: 0; axis.z: 0; axis.y: 1; angle: 0; origin.x: renderer.width / 2; origin.y: renderer.height / 2; }, @@ -75,8 +83,6 @@ Item { anchors.right: renderer.right anchors.margins: 20 wrapMode: Text.WordWrap - text: qsTr("The blue rectangle with the vintage 'Q' is an FBO, rendered by the application on the scene graph rendering thread. The FBO is managed and displayed using the QQuickFramebufferObject convenience class.") + text: qsTr("The blue rectangle with the vintage 'Q' is rendered by the application by directly using the QRhi APIs on the scene graph render thread. The custom QQuickItem then draws a quad textured with the QRhiTexture containing the custom 3D rendering.") } - - } diff --git a/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsb b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsb Binary files differnew file mode 100644 index 0000000000..31ad25de20 --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/checker.frag.qsb diff --git a/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.frag.qsb b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.frag.qsb Binary files differnew file mode 100644 index 0000000000..9a9cbaa82d --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.frag.qsb diff --git a/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.vert.qsb b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.vert.qsb Binary files differnew file mode 100644 index 0000000000..8626401364 --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/prebuilts_for_qmake/logo.vert.qsb diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp new file mode 100644 index 0000000000..92615a4d5b --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.cpp @@ -0,0 +1,443 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#include "rhitextureitem.h" +#include <QFile> + +RhiItemNode::RhiItemNode(RhiItem *item) + : m_item(item) +{ + m_window = m_item->window(); + connect(m_window, &QQuickWindow::beforeRendering, this, &RhiItemNode::render, + Qt::DirectConnection); + connect(m_window, &QQuickWindow::screenChanged, this, [this]() { + if (m_window->effectiveDevicePixelRatio() != m_dpr) + m_item->update(); + }, Qt::DirectConnection); +} + +QSGTexture *RhiItemNode::texture() const +{ + return m_sgTexture.get(); +} + +void RhiItemNode::sync() +{ + if (!m_rhi) { + m_rhi = m_window->rhi(); + if (!m_rhi) { + qWarning("No QRhi found for window %p, RhiItem will not be functional", m_window); + return; + } + } + + m_dpr = m_window->effectiveDevicePixelRatio(); + const int minTexSize = m_rhi->resourceLimit(QRhi::TextureSizeMin); + QSize newSize = QSize(qMax<int>(minTexSize, m_item->width()), + qMax<int>(minTexSize, m_item->height())) * m_dpr; + + bool needsNew = !m_sgTexture; + if (newSize != m_pixelSize) { + needsNew = true; + m_pixelSize = newSize; + } + + if (needsNew) { + QRhiTexture *texture = m_rhi->newTexture(QRhiTexture::RGBA8, m_pixelSize, 1, QRhiTexture::RenderTarget); + if (texture->create()) { + m_sgTexture.reset(m_window->createTextureFromRhiTexture(texture)); + setTexture(m_sgTexture.get()); + m_renderer->initialize(m_rhi, texture); + } else { + qWarning("Failed to create RhiItem texture of size %dx%d", m_pixelSize.width(), m_pixelSize.height()); + delete texture; + } + } + + m_renderer->synchronize(m_item); +} + +void RhiItemNode::render() +{ + // called before Qt Quick starts recording its main render pass + + if (!isValid() || !m_renderPending) + return; + + QRhiSwapChain *swapchain = m_window->swapChain(); + QSGRendererInterface *rif = m_window->rendererInterface(); + + // For completeness, handle both cases: on-screen QQuickWindow vs. + // off-screen QQuickWindow e.g. by using QQuickRenderControl to redirect + // into a texture. For the application's purposes just handling the first + // (swapchain is non-null) would be sufficient. + QRhiCommandBuffer *cb = swapchain ? swapchain->currentFrameCommandBuffer() + : static_cast<QRhiCommandBuffer *>( + rif->getResource(m_window, QSGRendererInterface::RhiRedirectCommandBuffer)); + + if (!cb) { + qWarning("Neither swapchain nor redirected command buffer are available."); + return; + } + + m_renderPending = false; + m_renderer->render(cb); + + markDirty(QSGNode::DirtyMaterial); + emit textureChanged(); +} + +void RhiItemNode::scheduleUpdate() +{ + m_renderPending = true; + m_window->update(); // ensure getting to beforeRendering() at some point +} + +RhiItem::RhiItem(QQuickItem *parent) + : QQuickItem(parent) +{ + setFlag(ItemHasContents); +} + +QSGNode *RhiItem::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +{ + // Changing to an empty size should not involve destroying and then later + // recreating the node, because we do not know how expensive the user's + // renderer setup is. Rather, keep the node if it already exist, and clamp + // all accesses to width and height. Hence the unusual !oldNode condition here. + if (!oldNode && (width() <= 0 || height() <= 0)) + return nullptr; + + RhiItemNode *n = static_cast<RhiItemNode *>(oldNode); + if (!n) { + if (!node) + node = new RhiItemNode(this); + if (!node->hasRenderer()) { + RhiItemRenderer *r = createRenderer(); + if (r) { + r->data = node; + node->setRenderer(r); + } else { + qWarning("No RhiItemRenderer was created; the item will not render"); + delete node; + node = nullptr; + return nullptr; + } + } + n = node; + } + + n->sync(); + + if (!n->isValid()) { + delete n; + node = nullptr; + return nullptr; + } + + if (window()->rhi()->isYUpInFramebuffer()) + n->setTextureCoordinatesTransform(QSGSimpleTextureNode::MirrorVertically); + + n->setFiltering(QSGTexture::Linear); + n->setRect(0, 0, qMax<int>(0, width()), qMax<int>(0, height())); + + n->scheduleUpdate(); + + return n; +} + +void RhiItem::geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) +{ + QQuickItem::geometryChange(newGeometry, oldGeometry); + if (newGeometry.size() != oldGeometry.size()) + update(); +} + +void RhiItem::releaseResources() +{ + // called on the gui thread if the item is removed from scene + + node = nullptr; +} + +void RhiItem::invalidateSceneGraph() +{ + // called on the render thread when the scenegraph is invalidated + + node = nullptr; +} + +bool RhiItem::isTextureProvider() const +{ + return true; +} + +QSGTextureProvider *RhiItem::textureProvider() const +{ + if (QQuickItem::isTextureProvider()) // e.g. if Item::layer::enabled == true + return QQuickItem::textureProvider(); + + if (!node) // create a node to have a provider, the texture will be null but that's ok + node = new RhiItemNode(const_cast<RhiItem *>(this)); + + return node; +} + +void RhiItemRenderer::update() +{ + if (data) + static_cast<RhiItemNode *>(data)->scheduleUpdate(); +} + +RhiItemRenderer *ExampleRhiItem::createRenderer() +{ + return new ExampleRhiItemRenderer; +} + +void ExampleRhiItem::setAngle(float a) +{ + if (m_angle == a) + return; + + m_angle = a; + emit angleChanged(); + update(); +} + +static QShader getShader(const QString &name) +{ + QFile f(name); + if (f.open(QIODevice::ReadOnly)) + return QShader::fromSerialized(f.readAll()); + + return QShader(); +} + +void ExampleRhiItemRenderer::initialize(QRhi *rhi, QRhiTexture *outputTexture) +{ + m_rhi = rhi; + + if (m_output && m_output != outputTexture) { + m_rt.reset(); + m_rp.reset(); + } + + m_output = outputTexture; + + if (!m_ds) { + m_ds.reset(m_rhi->newRenderBuffer(QRhiRenderBuffer::DepthStencil, m_output->pixelSize())); + m_ds->create(); + } else if (m_ds->pixelSize() != m_output->pixelSize()) { + m_ds->setPixelSize(m_output->pixelSize()); + m_ds->create(); + } + + if (!m_rt) { + m_rt.reset(m_rhi->newTextureRenderTarget({ { m_output }, m_ds.get() })); + m_rp.reset(m_rt->newCompatibleRenderPassDescriptor()); + m_rt->setRenderPassDescriptor(m_rp.get()); + m_rt->create(); + } + + if (!scene.vbuf) { + createGeometry(); + + const quint32 vsize = m_vertices.size() * 3 * sizeof(float); + const quint32 nsize = m_normals.size() * 3 * sizeof(float); + const quint32 vbufSize = vsize + nsize; + scene.vbuf.reset(m_rhi->newBuffer(QRhiBuffer::Immutable, QRhiBuffer::VertexBuffer, vbufSize)); + scene.vbuf->create(); + + scene.resourceUpdates = m_rhi->nextResourceUpdateBatch(); + scene.resourceUpdates->uploadStaticBuffer(scene.vbuf.get(), 0, vsize, m_vertices.constData()); + scene.resourceUpdates->uploadStaticBuffer(scene.vbuf.get(), vsize, nsize, m_normals.constData()); + + scene.ubuf.reset(m_rhi->newBuffer(QRhiBuffer::Dynamic, QRhiBuffer::UniformBuffer, 64)); + scene.ubuf->create(); + + scene.srb.reset(m_rhi->newShaderResourceBindings()); + scene.srb->setBindings({ + QRhiShaderResourceBinding::uniformBuffer(0, QRhiShaderResourceBinding::VertexStage, scene.ubuf.get()), + }); + scene.srb->create(); + + scene.ps.reset(m_rhi->newGraphicsPipeline()); + scene.ps->setDepthTest(true); + scene.ps->setDepthWrite(true); + scene.ps->setShaderStages({ + { QRhiShaderStage::Vertex, getShader(QLatin1String(":/scenegraph/rhitextureitem/shaders/logo.vert.qsb")) }, + { QRhiShaderStage::Fragment, getShader(QLatin1String(":/scenegraph/rhitextureitem/shaders/logo.frag.qsb")) } + }); + QRhiVertexInputLayout inputLayout; + inputLayout.setBindings({ + { 3 * sizeof(float) }, + { 3 * sizeof(float) } + }); + inputLayout.setAttributes({ + { 0, 0, QRhiVertexInputAttribute::Float3, 0 }, + { 1, 1, QRhiVertexInputAttribute::Float3, 0 } + }); + scene.ps->setVertexInputLayout(inputLayout); + scene.ps->setShaderResourceBindings(scene.srb.get()); + scene.ps->setRenderPassDescriptor(m_rp.get()); + scene.ps->create(); + } +} + +void ExampleRhiItemRenderer::synchronize(RhiItem *rhiItem) +{ + // called on the render thread (if there is one), while the main (gui) thread is blocked + + ExampleRhiItem *item = static_cast<ExampleRhiItem *>(rhiItem); + if (item->angle() != scene.logoAngle) + scene.logoAngle = item->angle(); +} + +void ExampleRhiItemRenderer::render(QRhiCommandBuffer *cb) +{ + QRhiResourceUpdateBatch *rub = scene.resourceUpdates; + if (rub) + scene.resourceUpdates = nullptr; + else + rub = m_rhi->nextResourceUpdateBatch(); + + const QMatrix4x4 matrix = m_rhi->clipSpaceCorrMatrix() * calculateModelViewMatrix(); + rub->updateDynamicBuffer(scene.ubuf.get(), 0, 64, matrix.constData()); + + const QColor clearColor = QColor::fromRgbF(0.5f, 0.5f, 0.7f, 1.0f); + cb->beginPass(m_rt.get(), clearColor, { 1.0f, 0 }, rub); + + cb->setGraphicsPipeline(scene.ps.get()); + const QSize outputSize = m_output->pixelSize(); + cb->setViewport(QRhiViewport(0, 0, outputSize.width(), outputSize.height())); + cb->setShaderResources(); + const QRhiCommandBuffer::VertexInput vbufBindings[] = { + { scene.vbuf.get(), 0 }, + { scene.vbuf.get(), quint32(m_vertices.size() * 3 * sizeof(float)) } + }; + cb->setVertexInput(0, 2, vbufBindings); + cb->draw(m_vertices.size()); + + cb->endPass(); +} + +void ExampleRhiItemRenderer::createGeometry() +{ + m_vertices.clear(); + m_normals.clear(); + + qreal x1 = +0.06f; + qreal y1 = -0.14f; + qreal x2 = +0.14f; + qreal y2 = -0.06f; + qreal x3 = +0.08f; + qreal y3 = +0.00f; + qreal x4 = +0.30f; + qreal y4 = +0.22f; + + quad(x1, y1, x2, y2, y2, x2, y1, x1); + quad(x3, y3, x4, y4, y4, x4, y3, x3); + + extrude(x1, y1, x2, y2); + extrude(x2, y2, y2, x2); + extrude(y2, x2, y1, x1); + extrude(y1, x1, x1, y1); + extrude(x3, y3, x4, y4); + extrude(x4, y4, y4, x4); + extrude(y4, x4, y3, x3); + + const qreal Pi = M_PI; + const int NumSectors = 100; + + for (int i = 0; i < NumSectors; ++i) { + qreal angle1 = (i * 2 * Pi) / NumSectors; + qreal x5 = 0.30 * sin(angle1); + qreal y5 = 0.30 * cos(angle1); + qreal x6 = 0.20 * sin(angle1); + qreal y6 = 0.20 * cos(angle1); + + qreal angle2 = ((i + 1) * 2 * Pi) / NumSectors; + qreal x7 = 0.20 * sin(angle2); + qreal y7 = 0.20 * cos(angle2); + qreal x8 = 0.30 * sin(angle2); + qreal y8 = 0.30 * cos(angle2); + + quad(x5, y5, x6, y6, x7, y7, x8, y8); + + extrude(x6, y6, x7, y7); + extrude(x8, y8, x5, y5); + } + + for (int i = 0; i < m_vertices.size(); i++) + m_vertices[i] *= 2.0f; +} + +void ExampleRhiItemRenderer::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4) +{ + m_vertices << QVector3D(x1, y1, -0.05f); + m_vertices << QVector3D(x2, y2, -0.05f); + m_vertices << QVector3D(x4, y4, -0.05f); + + m_vertices << QVector3D(x3, y3, -0.05f); + m_vertices << QVector3D(x4, y4, -0.05f); + m_vertices << QVector3D(x2, y2, -0.05f); + + QVector3D n = QVector3D::normal(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f)); + + m_normals << n; + m_normals << n; + m_normals << n; + + m_normals << n; + m_normals << n; + m_normals << n; + + m_vertices << QVector3D(x4, y4, 0.05f); + m_vertices << QVector3D(x2, y2, 0.05f); + m_vertices << QVector3D(x1, y1, 0.05f); + + m_vertices << QVector3D(x2, y2, 0.05f); + m_vertices << QVector3D(x4, y4, 0.05f); + m_vertices << QVector3D(x3, y3, 0.05f); + + n = QVector3D::normal(QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f)); + + m_normals << n; + m_normals << n; + m_normals << n; + + m_normals << n; + m_normals << n; + m_normals << n; +} + +void ExampleRhiItemRenderer::extrude(qreal x1, qreal y1, qreal x2, qreal y2) +{ + m_vertices << QVector3D(x1, y1, +0.05f); + m_vertices << QVector3D(x2, y2, +0.05f); + m_vertices << QVector3D(x1, y1, -0.05f); + + m_vertices << QVector3D(x2, y2, -0.05f); + m_vertices << QVector3D(x1, y1, -0.05f); + m_vertices << QVector3D(x2, y2, +0.05f); + + QVector3D n = QVector3D::normal(QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f)); + + m_normals << n; + m_normals << n; + m_normals << n; + + m_normals << n; + m_normals << n; + m_normals << n; +} + +QMatrix4x4 ExampleRhiItemRenderer::calculateModelViewMatrix() const +{ + QMatrix4x4 modelview; + modelview.rotate(scene.logoAngle, 0.0f, 1.0f, 0.0f); + modelview.rotate(scene.logoAngle, 1.0f, 0.0f, 0.0f); + modelview.rotate(scene.logoAngle, 0.0f, 0.0f, 1.0f); + modelview.translate(0.0f, -0.2f, 0.0f); + return modelview; +} diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h new file mode 100644 index 0000000000..d32ef34f11 --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.h @@ -0,0 +1,142 @@ +// Copyright (C) 2023 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +#ifndef RHITEXTUREITEM_H +#define RHITEXTUREITEM_H + +#include <QQuickItem> +#include <QSGSimpleTextureNode> +#include <QSGTextureProvider> +#include <rhi/qrhi.h> + +class LogoRenderer; +class RhiItem; +class RhiItemNode; + +QT_FORWARD_DECLARE_CLASS(QSGPlainTexture) + +class RhiItemRenderer +{ +public: + virtual ~RhiItemRenderer() { } + virtual void initialize(QRhi *rhi, QRhiTexture *outputTexture) = 0; + virtual void synchronize(RhiItem *item) = 0; + virtual void render(QRhiCommandBuffer *cb) = 0; + + void update(); + +private: + void *data; + friend class RhiItem; +}; + +//! [itembase] +class RhiItem : public QQuickItem +{ + Q_OBJECT +public: + RhiItem(QQuickItem *parent = nullptr); + + virtual RhiItemRenderer *createRenderer() = 0; + +protected: + QSGNode *updatePaintNode(QSGNode *, UpdatePaintNodeData *) override; + void geometryChange(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void releaseResources() override; + bool isTextureProvider() const override; + QSGTextureProvider *textureProvider() const override; + +private Q_SLOTS: + void invalidateSceneGraph(); + +private: + mutable RhiItemNode *node = nullptr; +}; +//! [itembase] + +//! [itemnode] +class RhiItemNode : public QSGTextureProvider, public QSGSimpleTextureNode +//! [itemnode] +{ + Q_OBJECT + +public: + RhiItemNode(RhiItem *item); + + QSGTexture *texture() const override; + + void sync(); + bool isValid() const { return m_rhi && m_sgTexture; } + void scheduleUpdate(); + bool hasRenderer() const { return m_renderer != nullptr; } + void setRenderer(RhiItemRenderer *r) { m_renderer.reset(r); } + void setMirrorVertically(bool b); + +private slots: + void render(); + +private: + RhiItem *m_item; + QQuickWindow *m_window; + QSize m_pixelSize; + qreal m_dpr = 0.0f; + QRhi *m_rhi = nullptr; + bool m_renderPending = true; + std::unique_ptr<QSGTexture> m_sgTexture; + std::unique_ptr<RhiItemRenderer> m_renderer; +}; + +//! [item] +class ExampleRhiItem : public RhiItem +{ + Q_OBJECT + QML_NAMED_ELEMENT(ExampleRhiItem) + Q_PROPERTY(float angle READ angle WRITE setAngle NOTIFY angleChanged) + +public: + float angle() const { return m_angle; } + void setAngle(float a); + + RhiItemRenderer *createRenderer() override; + +signals: + void angleChanged(); + +private: + float m_angle = 0.0f; +}; +//! [item] + +class ExampleRhiItemRenderer : public RhiItemRenderer +{ +public: + void initialize(QRhi *rhi, QRhiTexture *outputTexture) override; + void synchronize(RhiItem *item) override; + void render(QRhiCommandBuffer *cb) override; + +private: + QRhi *m_rhi = nullptr; + QRhiTexture *m_output = nullptr; + std::unique_ptr<QRhiRenderBuffer> m_ds; + std::unique_ptr<QRhiTextureRenderTarget> m_rt; + std::unique_ptr<QRhiRenderPassDescriptor> m_rp; + + struct { + QRhiResourceUpdateBatch *resourceUpdates = nullptr; + std::unique_ptr<QRhiBuffer> vbuf; + std::unique_ptr<QRhiBuffer> ubuf; + std::unique_ptr<QRhiShaderResourceBindings> srb; + std::unique_ptr<QRhiGraphicsPipeline> ps; + float logoAngle = 0.0f; + } scene; + + void createGeometry(); + void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4); + void extrude(qreal x1, qreal y1, qreal x2, qreal y2); + QMatrix4x4 calculateModelViewMatrix() const; + + QList<QVector3D> m_vertices; + QList<QVector3D> m_normals; +}; + +#endif diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro new file mode 100644 index 0000000000..4d5c132a42 --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.pro @@ -0,0 +1,16 @@ +QT += gui-private qml quick + +CONFIG += qmltypes +QML_IMPORT_NAME = SceneGraphRendering +QML_IMPORT_MAJOR_VERSION = 1 + +HEADERS += rhitextureitem.h +SOURCES += rhitextureitem.cpp main.cpp + +RESOURCES += rhitextureitem.qrc + +target.path = $$[QT_INSTALL_EXAMPLES]/quick/scenegraph/rhitextureitem +INSTALLS += target + +OTHER_FILES += \ + main.qml diff --git a/examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc new file mode 100644 index 0000000000..c507ac33c2 --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/rhitextureitem.qrc @@ -0,0 +1,8 @@ +<RCC> + <qresource prefix="/scenegraph/rhitextureitem"> + <file>main.qml</file> + <file alias="shaders/logo.vert.qsb">prebuilts_for_qmake/logo.vert.qsb</file> + <file alias="shaders/logo.frag.qsb">prebuilts_for_qmake/logo.frag.qsb</file> + <file alias="shaders/checker.frag.qsb">prebuilts_for_qmake/checker.frag.qsb</file> + </qresource> +</RCC> diff --git a/examples/quick/scenegraph/fboitem/shaders/checker.frag b/examples/quick/scenegraph/rhitextureitem/shaders/checker.frag index 1e4131d026..d62eceec8f 100644 --- a/examples/quick/scenegraph/fboitem/shaders/checker.frag +++ b/examples/quick/scenegraph/rhitextureitem/shaders/checker.frag @@ -1,22 +1,23 @@ #version 440 layout(std140, binding = 0) uniform buf { + // built-in Qt data mat4 qt_Matrix; float qt_Opacity; - + // custom data vec4 color1; vec4 color2; vec2 pixelSize; -} ubuf; +}; layout(location = 0) in vec2 qt_TexCoord0; layout(location = 0) out vec4 fragColor; void main() { - vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * ubuf.pixelSize)); + vec2 tc = sign(sin(3.14159265358979323846 * qt_TexCoord0 * pixelSize)); if (tc.x != tc.y) - fragColor = ubuf.color1; + fragColor = color1; else - fragColor = ubuf.color2; + fragColor = color2; } diff --git a/examples/quick/scenegraph/rhitextureitem/shaders/logo.frag b/examples/quick/scenegraph/rhitextureitem/shaders/logo.frag new file mode 100644 index 0000000000..1e2101776d --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/shaders/logo.frag @@ -0,0 +1,9 @@ +#version 440 + +layout(location = 0) in vec4 v_color; +layout(location = 0) out vec4 fragColor; + +void main() +{ + fragColor = v_color; +} diff --git a/examples/quick/scenegraph/rhitextureitem/shaders/logo.vert b/examples/quick/scenegraph/rhitextureitem/shaders/logo.vert new file mode 100644 index 0000000000..5a2aa7f504 --- /dev/null +++ b/examples/quick/scenegraph/rhitextureitem/shaders/logo.vert @@ -0,0 +1,19 @@ +#version 440 + +layout(location = 0) in vec4 vertex; +layout(location = 1) in vec3 normal; + +layout(location = 0) out vec4 v_color; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; +}; + +void main() +{ + vec3 toLight = normalize(vec3(0.0, 0.3, 1.0)); + float angle = max(dot(normal, toLight), 0.0); + vec3 col = vec3(0.40, 1.0, 0.0); + v_color = clamp(vec4(col * 0.2 + col * 0.8 * angle, 1.0), 0.0, 1.0); + gl_Position = matrix * vertex; +} diff --git a/examples/quick/scenegraph/scenegraph.pro b/examples/quick/scenegraph/scenegraph.pro index 85dd7bd439..c37e822680 100644 --- a/examples/quick/scenegraph/scenegraph.pro +++ b/examples/quick/scenegraph/scenegraph.pro @@ -2,8 +2,7 @@ TEMPLATE = subdirs qtConfig(opengl(es1|es2)?) { SUBDIRS += \ - fboitem \ - openglunderqml \ + openglunderqml } SUBDIRS += \ @@ -12,7 +11,8 @@ SUBDIRS += \ graph \ threadedanimation \ twotextureproviders \ - rhiunderqml + rhiunderqml \ + rhitextureitem macos|ios { SUBDIRS += \ diff --git a/examples/quick/scenegraph/shared/logorenderer.cpp b/examples/quick/scenegraph/shared/logorenderer.cpp deleted file mode 100644 index b95ae0d21d..0000000000 --- a/examples/quick/scenegraph/shared/logorenderer.cpp +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#include "logorenderer.h" -#include <QPainter> -#include <QPaintEngine> -#include <qmath.h> - -LogoRenderer::LogoRenderer() -{ -} - -LogoRenderer::~LogoRenderer() -{ -} - - -void LogoRenderer::paintQtLogo() -{ - program1.enableAttributeArray(normalAttr1); - program1.enableAttributeArray(vertexAttr1); - program1.setAttributeArray(vertexAttr1, vertices.constData()); - program1.setAttributeArray(normalAttr1, normals.constData()); - glDrawArrays(GL_TRIANGLES, 0, vertices.size()); - program1.disableAttributeArray(normalAttr1); - program1.disableAttributeArray(vertexAttr1); -} - - -void LogoRenderer::initialize() -{ - initializeOpenGLFunctions(); - - glClearColor(0.1f, 0.1f, 0.2f, 1.0f); - - const char *vsrc1 = - "attribute highp vec4 vertex;\n" - "attribute mediump vec3 normal;\n" - "uniform mediump mat4 matrix;\n" - "varying mediump vec4 color;\n" - "void main(void)\n" - "{\n" - " vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n" - " float angle = max(dot(normal, toLight), 0.0);\n" - " vec3 col = vec3(0.40, 1.0, 0.0);\n" - " color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);\n" - " color = clamp(color, 0.0, 1.0);\n" - " gl_Position = matrix * vertex;\n" - "}\n"; - - const char *fsrc1 = - "varying mediump vec4 color;\n" - "void main(void)\n" - "{\n" - " gl_FragColor = color;\n" - "}\n"; - - program1.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vsrc1); - program1.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fsrc1); - program1.link(); - - vertexAttr1 = program1.attributeLocation("vertex"); - normalAttr1 = program1.attributeLocation("normal"); - matrixUniform1 = program1.uniformLocation("matrix"); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - - m_fAngle = 0; - m_fScale = 1; - createGeometry(); -} - -void LogoRenderer::render() -{ - glDepthMask(true); - - glClearColor(0.5f, 0.5f, 0.7f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - - glFrontFace(GL_CW); - glCullFace(GL_FRONT); - glEnable(GL_CULL_FACE); - glEnable(GL_DEPTH_TEST); - - QMatrix4x4 modelview; - modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f); - modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f); - modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f); - modelview.scale(m_fScale); - modelview.translate(0.0f, -0.2f, 0.0f); - - program1.bind(); - program1.setUniformValue(matrixUniform1, modelview); - paintQtLogo(); - program1.release(); - - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - - m_fAngle += 1.0f; -} - -void LogoRenderer::createGeometry() -{ - vertices.clear(); - normals.clear(); - - qreal x1 = +0.06f; - qreal y1 = -0.14f; - qreal x2 = +0.14f; - qreal y2 = -0.06f; - qreal x3 = +0.08f; - qreal y3 = +0.00f; - qreal x4 = +0.30f; - qreal y4 = +0.22f; - - quad(x1, y1, x2, y2, y2, x2, y1, x1); - quad(x3, y3, x4, y4, y4, x4, y3, x3); - - extrude(x1, y1, x2, y2); - extrude(x2, y2, y2, x2); - extrude(y2, x2, y1, x1); - extrude(y1, x1, x1, y1); - extrude(x3, y3, x4, y4); - extrude(x4, y4, y4, x4); - extrude(y4, x4, y3, x3); - - const qreal Pi = M_PI; - const int NumSectors = 100; - - for (int i = 0; i < NumSectors; ++i) { - qreal angle1 = (i * 2 * Pi) / NumSectors; - qreal x5 = 0.30 * sin(angle1); - qreal y5 = 0.30 * cos(angle1); - qreal x6 = 0.20 * sin(angle1); - qreal y6 = 0.20 * cos(angle1); - - qreal angle2 = ((i + 1) * 2 * Pi) / NumSectors; - qreal x7 = 0.20 * sin(angle2); - qreal y7 = 0.20 * cos(angle2); - qreal x8 = 0.30 * sin(angle2); - qreal y8 = 0.30 * cos(angle2); - - quad(x5, y5, x6, y6, x7, y7, x8, y8); - - extrude(x6, y6, x7, y7); - extrude(x8, y8, x5, y5); - } - - for (int i = 0;i < vertices.size();i++) - vertices[i] *= 2.0f; -} - -void LogoRenderer::quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4) -{ - vertices << QVector3D(x1, y1, -0.05f); - vertices << QVector3D(x2, y2, -0.05f); - vertices << QVector3D(x4, y4, -0.05f); - - vertices << QVector3D(x3, y3, -0.05f); - vertices << QVector3D(x4, y4, -0.05f); - vertices << QVector3D(x2, y2, -0.05f); - - QVector3D n = QVector3D::normal - (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(x4 - x1, y4 - y1, 0.0f)); - - normals << n; - normals << n; - normals << n; - - normals << n; - normals << n; - normals << n; - - vertices << QVector3D(x4, y4, 0.05f); - vertices << QVector3D(x2, y2, 0.05f); - vertices << QVector3D(x1, y1, 0.05f); - - vertices << QVector3D(x2, y2, 0.05f); - vertices << QVector3D(x4, y4, 0.05f); - vertices << QVector3D(x3, y3, 0.05f); - - n = QVector3D::normal - (QVector3D(x2 - x4, y2 - y4, 0.0f), QVector3D(x1 - x4, y1 - y4, 0.0f)); - - normals << n; - normals << n; - normals << n; - - normals << n; - normals << n; - normals << n; -} - -void LogoRenderer::extrude(qreal x1, qreal y1, qreal x2, qreal y2) -{ - vertices << QVector3D(x1, y1, +0.05f); - vertices << QVector3D(x2, y2, +0.05f); - vertices << QVector3D(x1, y1, -0.05f); - - vertices << QVector3D(x2, y2, -0.05f); - vertices << QVector3D(x1, y1, -0.05f); - vertices << QVector3D(x2, y2, +0.05f); - - QVector3D n = QVector3D::normal - (QVector3D(x2 - x1, y2 - y1, 0.0f), QVector3D(0.0f, 0.0f, -0.1f)); - - normals << n; - normals << n; - normals << n; - - normals << n; - normals << n; - normals << n; -} diff --git a/examples/quick/scenegraph/shared/logorenderer.h b/examples/quick/scenegraph/shared/logorenderer.h deleted file mode 100644 index 06c49baab1..0000000000 --- a/examples/quick/scenegraph/shared/logorenderer.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright (C) 2017 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause - -#ifndef LOGORENDERER_H -#define LOGORENDERER_H - -#include <QtGui/qvector3d.h> -#include <QtGui/qmatrix4x4.h> -#include <qopenglshaderprogram.h> -#include <qopenglfunctions.h> - -#include <QTime> -#include <QList> - -class LogoRenderer : protected QOpenGLFunctions -{ -public: - LogoRenderer(); - ~LogoRenderer(); - - void render(); - void initialize(); - -private: - - qreal m_fAngle; - qreal m_fScale; - - void paintQtLogo(); - void createGeometry(); - void quad(qreal x1, qreal y1, qreal x2, qreal y2, qreal x3, qreal y3, qreal x4, qreal y4); - void extrude(qreal x1, qreal y1, qreal x2, qreal y2); - - QList<QVector3D> vertices; - QList<QVector3D> normals; - QOpenGLShaderProgram program1; - int vertexAttr1; - int normalAttr1; - int matrixUniform1; -}; -#endif |
